Django--用户认证组件auth(登录用-依赖session,其他用)

一、用户认证组件auth介绍

二、auth_user表添加用户信息

三、auth使用示例

四、auth封装的认证装饰器

五、自定义

一、用户认证组件auth介绍

解决的问题:

之前是把is_login=True放在session里来判断用户是否登录
之前的操作,在覆盖的时候有问题。
例如两个用户先后登录,第一个用户key-value比较多,第二个key-value少,覆盖后可能会保留有第一个的key-value

能做的事:1,验证用户名密码是否正确  2、判断用户是否已登录,用session保存用户登录状态

用户认证组件的前提:
功能:用session记录登录验证状态(不记录上次登录时间那些)
前提:不能用自己的用户表了。账号密码要放在Django自带的auth_user用户组件认证表。
不妨碍扩展其他字段。用这个表和其他表做一对一,一对多等

二、auth_user表添加用户信息

创建超级用户:python manage.py createsuperuser

创建普通用户:python manage.py createuser

三、auth使用示例

API
封装在auth模块中了:

--------------------------------------------------

from django.contrib import auth
def login(request):
  user=request.POST.get("user")
  pwd=request.POST.get("pwd")
    # 验证用户名密码是否正确
    # 如果验证通过返回user对象,不通过返回None
    # PS:可以自己来吗?from django.contrib.auth.models import User
    # 不得行,因为密码是加了密的,而且没必要干重复的事
  user=auth.authenticate(username=user,password=pwd)
  if user:
    # 如果验证通过,就注册登录信息
    auth.login(request, user)
    # 一旦注册session,把这个就变成了request.user
    # 在所有的视图函数和模板(模板里不用传都能用)都可以直接使用request.user
    # request.user表示当前登录对象 request.user==user
    # 没有登录是匿名对象,AnonymousUser,
      # request.user.is_anonymous或request.user.id==None
      #或request.user.user==''或request.user.is_authenticated 来判断用户是否登录

---------------------------------------------------------

注册用户

def reg(request):
  user=request.POST.get("user")
  pwd=request.POST.get("pwd")
  User.objects.create_user(username=user,password=pwd)    # 还有create_superuser方法,密码入库是加密的
  #改密码
  user = User.objects.get(username='')
  user.set_password(password='abc')
  user.save()

--------------------------------------------------------

总结:
from django.contrib import auth
1.验证登录:user=auth.authenticate(username=user,password=pwd)
2.注册登录:user=auth.login(request, user)
3.注销:auth.logout(request)

4.是否已经登录:request.user.is_authenticated
5.添加用户:User.objects.create_user(username=user,password=pwd)

PS:
request.user是一个全局变量。可以在视图中使用,在模板中不用传参可以直接用
补充:
如果是匿名用户对象:
request.user.is_anonymous==True
request.user.id==None
request.user.user==''


四、auth封装的认证装饰器

比如很多视图函数都要  “已经登录才能访问”的要求
可以用Django自带的装饰器解决 @login_required
不认证跳转到LOGIN_URL="/login/"是自己在settings.py里配的
但实际跳转是到:127.0.0.1:8000/login/?next=/order/
所以在视图函数中:
登录成功应该重定向到return redirect(request.GET.get("next","/index/"))

后台login视图↘

def login(request):
if request.method == "GET":
return render(request, 'login.html')
if request.method == 'POST':
# 获取发来的数据
user = request.POST.get("user")
pwd = request.POST.get("pwd")
valid_code = request.POST['valid_code']
# 获取session中的验证码
valid_code_str = request.session.get("valid_code_str")

response = {"user": None, "msg": None, "next": None}
if valid_code.upper() == valid_code_str.upper():
# 验证码正确
user = auth.authenticate(username=user, password=pwd)
if user:
# 如果验证成功就注册登录信息
auth.login(request, user)
response["user"] = user.username
response["msg"] = "ok"
response["next"] = request.GET.get("next", "/index/")
else:
response["msg"] = "username or password error!"
else:
# 验证码错误
response["msg"] = "validCode error"
return JsonResponse(response)

前端收到json后的回调函数↘

success:function(data){
console.log(data);
if(data.user){
location.href=data.next;
}else{
$("#error").text(data.msg);
setTimeout(function () {
$("#error").text('');
},3000);
}
}


from django.contrib.auth.decorators import login_required

@login_required
def order(request):
  # if not request.user.is_authenticated:
    # return redirect("/login/")
  return render(request,"order.html")

五、自定义auth认证后端,亲测可用

作用是给自定义的User表使用Django自带那一套auth认证,用法见views

----------------settings.py------------

AUTH_USER_MODEL = 'web.UserInfo'

AUTHENTICATION_BACKENDS = (
'web.backends.UserAuthBackend',
)

-----------------models.py-----------------

import unicodedata
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth import password_validation
from django.contrib.auth.hashers import (
check_password, is_password_usable, make_password,
)
from django.db import models
from django.utils.crypto import salted_hmac


class MyUserManager(BaseUserManager):
use_in_migrations = True

def _create_user(self, username, password, **extra_fields):
if not username:
raise ValueError('The given username must be set')
username = self.model.normalize_username(username)
user = self.model(username=username, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user

def create_user(self, username, password=None, **extra_fields):
return self._create_user(username, password, **extra_fields)


class UserInfo(models.Model):
username = models.CharField(max_length=150, unique=True, )
password = models.CharField(max_length=128)
is_active = models.BooleanField(default=True, help_text="默认为活动状态,如果设置为非活动状态,后端认证必定失败,相当于删除用户")
# Stores the raw password if set_password() is called so that it can
# be passed to password_changed() after the model is saved.
_password = None
objects = MyUserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []

def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self._password is not None:
password_validation.password_changed(self._password, self)
self._password = None

def clean(self):
setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username()))

def get_username(self):
"""Return the username for this User."""
return getattr(self, self.USERNAME_FIELD)

def natural_key(self):
return (self.get_username(),)

@property
def is_anonymous(self):
"""
Always return False. This is a way of comparing User objects to
anonymous users.
"""
return False

@property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True

def set_password(self, raw_password):
self.password = make_password(raw_password)
self._password = raw_password

def check_password(self, raw_password):
"""
Return a boolean of whether the raw_password was correct. Handles
hashing formats behind the scenes.
"""

def setter(raw_password):
self.set_password(raw_password)
# Password hash upgrades shouldn't be considered password changes.
self._password = None
self.save(update_fields=["password"])

return check_password(raw_password, self.password, setter)

def set_unusable_password(self):
# Set a value that will never be a valid hash
self.password = make_password(None)

def has_usable_password(self):
"""
Return False if set_unusable_password() has been called for this user.
"""
return is_password_usable(self.password)

def get_session_auth_hash(self):
"""
Return an HMAC of the password field.
"""
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
return salted_hmac(key_salt, self.password).hexdigest()

@classmethod
def normalize_username(cls, username):
return unicodedata.normalize('NFKC', username) if isinstance(username, str) else username

-----------------------------backends.py----------------------------------------------------

from django.contrib.auth import get_user_model

UserModel = get_user_model()


class UserAuthBackend:
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user

def user_can_authenticate(self, user):
"""
Reject users with is_active=False. Custom user models that don't have
that attribute are allowed.
"""
is_active = getattr(user, 'is_active', None)
return is_active or is_active is None

def get_user(self, user_id):
try:
user = UserModel._default_manager.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None

------根urls.py--------------------

from django.urls import path
from web import views
urlpatterns = [
path('login/', views.login),
path('logout/', views.logout),
path('index/', views.index),
]

---------views.py----------------------

from django.shortcuts import HttpResponse, render, redirect
from web.models import UserInfo
from django.contrib.auth.decorators import login_required
from django.contrib import auth


@login_required(login_url='/login/')
def index(request):
return HttpResponse("系统首页............欢迎您~~~~~")


def login(request):
if request.method == 'GET':
return render(request, 'login.html')
username, pwd = request.POST.get('username'), request.POST.get('pwd')
print(username, pwd)
user = auth.authenticate(username=username, password=pwd)
if user:
auth.login(request, user)
next_url = request.GET.get("next", "/index/")
return redirect(next_url)
return HttpResponse("登录失败")


def change_pwd(request):
if request.method == 'GET':
return render(request, 'login.html')
username, pwd = request.POST.get('username'), request.POST.get('pwd')
print(username, pwd)
user = UserInfo.objects.filter(username=username).first()
# 设置密码
user.set_password('777')
user.save()
# 将密码变为永远不可用
# user.set_unusable_password()
# user.save()
# 判断密码是否匹配
is_pass = UserInfo.objects.filter(username=username).first().check_password(pwd)
print(is_pass)
# 判断用户密码是否可用,可用返回True,不可用返回False
print(user.has_usable_password())
return HttpResponse("ok")


def logout(request):
auth.logout(request)
return redirect('/login/')

---------

原文地址:https://www.cnblogs.com/staff/p/10738088.html