zoukankan      html  css  js  c++  java
  • 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")
    
  • 相关阅读:
    ajax专题
    luogu P1346 电车 最短路
    luogu P1462 通往奥格瑞玛的道路 最短路
    luogu P1328 生活大爆炸版石头剪刀布
    luogu P1315 联合权值 枚举
    luogu P1156 垃圾陷阱 背包问题
    luogu P1217 回文质数 枚举
    luogu P3650 滑雪课程设计 枚举
    luogu1209 修理牛棚 贪心
    luogu P1223 排队接水 贪心
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/11773818.html
Copyright © 2011-2022 走看看