• Django框架之 auth认证模块


    一、Auth模块是什么

    Auth模块是Django自带的用户认证模块:

    我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。

    Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

    用auth模块 你就用全套 不是自己写一部分 用别人一部分

    二、Auth模块的使用

    • 创建超级用户 用于登录django admin的后台管理
    # 必须先有数据库,配置完数据库,执行数据库迁移命令之后
    # 再通过 Pycharm中的Tools-> Run manage.py Task
    
    数据命令: createsuperuser
    # 然后输入账号、邮箱、密码(注意:密码必须数字加字母并且超过8位)、确认密码、
    
    • auth模块导入
    from django.contrib import auth
    
    • 校验用户是否存在
    '''通过auth模块校验用户是否存在'''
    # 返回的是数据对象  没有返回None
    user_obj = auth.authenticate(username=username,password=password)
    
    • 保存用户登录状态

      该函数接受一个HttpRequest对象,以及一个经过认证的User对象。

      该函数实现一个用户登录的功能。它本质上会在后端为该用户生成相关session数据。

    '''通过auth模块记录用户状态 才算真正的用户登录
    该方法会帮你操作session表 并且只要执行了该方法
    就可以在任何位置通过request.user获取到当前登录的用户对象
    '''
    auth.login(request, user_obj)
    
    • 获取当前用户数据对象
    '''登陆成功后'''
    print(request.user)  # 通过request.user直接拿到登录用户的用户对象
    print(request.user.username)	# 通过操作orm的方式 对象.字段名
    print(request.user.password)	# 通过操作orm的方式 对象.字段名
    
    • 判断当前用户是否登录
    '''登陆成功后'''
    print(request.user.is_authenticated())  # 简单快捷的判断用户是否登录
    
    • 登出,并清除session信息

      该函数接受一个HttpRequest对象,无返回值。

      当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

    '''登陆成功后'''
    auth.logout(request)    # 登出并清除用户session信息
    
    • 校验用户是否登录的装饰器

      auth 给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验。

      没有登陆则去指定url登陆,登陆成功后重定向之前想要访问的url

      但是使用时必须指定登陆后重定向的地址,否则django默认去 /accounts/login/ 登陆

    '''校验用户登陆装饰器 两种用法'''
    from django.contrib.auth.decorators import login_required
    
    # 第一种用法
    @login_required(login_url="/app01/auth_login/")  # 局部配置,去指定路径登陆
    # 第二种用法
    #@login_required  # 全局配置,再settings中配置,否则默认去/accounts/login/中登陆
    def auth_home(request):
        '''登陆成功后'''
        print(request.user)  # 直接拿到登录用户的用户对象
        print(request.user.password)
        print(request.user.is_authenticated())  # 简单快捷的判断用户是否登录
        return HttpResponse(f"登陆成功 {request.user.username}")
    
    '''auth登录的装饰器 settings.py 配置内容'''
    LOGIN_URL = '/login/'
    
    • 校验原密码是否正确

      auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。

      密码正确返回True,否则返回False。

    '''校验密码是否正确'''
    is_right = request.user.check_password(old_pwd)
    
    • 设置新密码

      要先登陆不然无法设置

      auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。

      注意:设置完一定要调用用户对象的save方法!!!

    '''修改密码'''
    request.user.set_password(new_pwd)
    request.user.save()  # 一定要点save方法保存 才能真正的操作数据库
    
    • 创建普通用户

      auth 提供的一个创建新用户的方法,需要提供必要参数(username、password)等。

      注意:这里不能再用 orm的 create 方法去创建用户名记录了,因为这个方法创建的是明文

    # 导入认证模型表的User
    from django.contrib.auth.models import User
    
    '''创建普通用户 密码是密文 邮箱字段选填'''
    User.objects.create_user(username=user, password=pwd)
    
    • 创建超级用户(管理员)

      只有管理员用户,才能登入django的admin后台

      auth 提供的一个创建新的超级用户的方法,需要提供必要参数(username、password、email)。

    '''创建超级用户  邮箱字段必须填写'''
    User.objects.create_superuser(username=user,password=pwd,email='123@qq.com')
    

    2.1 User对象的属性

    User对象属性:username, password

    is_staff : 用户是否拥有网站的管理权限.

    is_active : 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。

    三、扩展auth_user表的字段

    我们知道auth_user表是在执行数据库迁移命令时自动创建的

    django中间件帮我们在请求来的时候通过auth_user表进行用户身份校验

    那问题来了,我们如何改auth_user表呢?增加或删除字段?

    3.1 通过AbstractUser类来进行扩展

    1. 首先导入auth认证组件中的AbstractUser类
      from django.contrib.auth.models import AbstractUser

    2. 自己写一个类 继承原来的auth_user类

      注意:你继承了AbstractUser之后 你自定义的表中 字段不能跟原有的冲突

    '''扩展 auth认证组件中 auth_user表'''
    from django.contrib.auth.models import AbstractUser
    class My_User(AbstractUser):
    """
    强调 你继承了AbstractUser之后 你自定义的表中 字段不能跟原有的冲突
    """
    phone = models.BigIntegerField()
    avatar = models.FileField()
    register_time = models.DateField(auto_now_add=Tr
    
    1. 在settings配置文件中 告诉django使用你新建的类来替代auth_user表

      固定语法: AUTH_USER_MODEL = '应用名.表名'

      坑点:不能在以有库上直接在迁移一次数据库。只能用新的数据库,并且没有数据库迁移记录。

    '''settings.py'''
    
    # auth自定义表配置
    AUTH_USER_MODEL = 'app01.My_User'
    # 固定语法: AUTH_USER_MODEL = '应用名.表名
    

    通过上面的方式 继承的表 还可以继续使用auth模块所有的功能

    再次注意:

    一旦我们指定了新的认证系统所使用的表,我们就需要重新在数据库中创建该表,而不能继续使用原来默认的auth_user表了。

    扩展:实现功能的插拔式设计

    参看django 中间件配置 实现功能的插拔式设计(重在思想)

    • 实例: 现在有一个需求,任务紧急,需要通过手机,微信,短信,等方式群发信息。但不限于使用某一类通讯器材。

    这时候,你发现要发送的内容都一样,而且使用的模块却可以根据任务需求来随机使用。如果你一个个去写,会很麻烦。假如今天用这个,明天用那个,那你岂不是要改累死了。

    于是,我们模拟实现一个功能的可插拔是设计:

    '''app01/settings.py
    暴露给用户的配置文件,如果你要添加或者修改,只需要改这里即可
    '''
    
    INSTALLED_APPS = [
        # "set_module_test.app01.send_msg.Msg",   # 项目名,应用名,文件名,类名
        "set_module_test.app01.send_email.Email",   # 项目名,应用名,文件名,类名
        "set_module_test.app01.send_phone.Phone",  # 项目名,应用名,文件名,类名
    ]
    
    '''default_module/default_settings.py
    系统默认的配置文件,会首先导入
    '''
    
    INSTALLED_APPS = [
        "set_module_test.default_module.send_phone.Phone",   # 项目名,应用名,文件名,类名
    ]
    
    '''default_module/__init__
    包中的__init__,还记得导包就是导init这句话嘛
    最重要的代码都在这里了
    '''
    
    from set_module_test import settings
    from set_module_test.default_module import default_settings
    import importlib
    
    def run(content):
        Setup().send(content)
    
    class Setup():
        def __init__(self):
            for app in dir(default_settings):
                if app.isupper():
                    lib_list = getattr(default_settings, app)
                    for lib in lib_list:
                        module, class_name = lib.rsplit(".", maxsplit=1)
                        # importlib用法,导入模块,或包,最多到文件
                        mod = importlib.import_module(module)
                        setattr(self, class_name, getattr(mod, class_name))
    
            for app in dir(settings):
                if app.isupper():
                    lib_list = getattr(settings, app)
                    for lib in lib_list:
                        module, class_name = lib.rsplit(".", maxsplit=1)
                        # importlib用法,导入模块,或包,最多到文件
                        mod = importlib.import_module(module)
                        setattr(self, class_name, getattr(mod, class_name))
    
        def send(self,content):
            for key,func in self.__dict__.items():
                func().send(content)
    
    '''用户实现 app01/send_msg'''
    class Msg():
        def send(self,content):
            print("Msg",content)
    
    '''用户实现 app01/send_email'''
    
    class Email():
        def send(self,content):
            print("Email",content)
            
    '''用户实现 app01/send_phone'''
    class Phone():
        def send(self,content):
            print("用户Phone",content)
    
    '''run 系统运行文件'''
    
    from set_module_test import default_module
    '''
    实现功能的可插拔式设计
    '''
    
    if __name__ == '__main__':
        default_module.run("123")
    
  • 相关阅读:
    [PHP] php调用不存在的方法会自动调用 __call 魔术方法
    [PHP] laravel框架响应json信息中文禁止unicode编码
    [PHP] php中的trait代码复用方式
    [nginx] 解决:upstream timed out (110: Connection timed out) while reading response header from upstream
    [linux] Linux下格式化JSON程序-jq
    [git] Git Clean 清除 untrack 没有加入版本库的文件
    goland终端如何导入github上的包
    calico 配置 BGP Route Reflectors
    改善 Kubernetes 上的 JVM 预热问题
    golang开源对象存储
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/11773818.html
Copyright © 2020-2023  润新知