zoukankan      html  css  js  c++  java
  • 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/')

    ---------

  • 相关阅读:
    Java操作redis
    Ajax & Json
    【转载】K8s-Pod时区与宿主时区时区同步
    【转载】Python中如何将字符串作为变量名
    【转载】python实现dubbo接口的调用
    机器学习避坑指南:训练集/测试集分布一致性检查
    机器学习深度研究:特征选择中几个重要的统计学概念
    机器学习数学基础:学习线性代数,千万不要误入歧途!推荐一个正确学习路线
    被 Pandas read_csv 坑了
    print('Hello World!')的新玩法
  • 原文地址:https://www.cnblogs.com/staff/p/10738088.html
Copyright © 2011-2022 走看看