65、Django之认证模块Auth

Django框架 / 2021-03-03

参考博客:博客园-JsonJi,原文链接:https://www.cnblogs.com/Dominic-Ji/p/10881136.html

一、Auth模块是什么?

在开发一个网站的时候,不可避免要设计用户系统,它涉及到用户注册、登陆、注销、认证、修改密码等等功能;而此前我们学习cookie与session时纯手写登陆认证功能,显得十分笨拙。

Django深谙此道,它为我们提供了一个强大的用户认证模块:auth!在我们创建好一个Django项目后直接执行数据库迁移命令后,会自动生成很多表,其中session表已经接触过,还有一张重要的就是auth_user表,它为auth模块服务!

Django在启动之后就可以直接访问admin路由,它需要输入账号密码,而它的账号数据用的就是auth_user表,并且还必须是管理员用户才能进入。

二、Auth常用方法

此次学习我们将依赖于auth_user表完成用户认证的所有功能!

2.1、创建超级用户

super user,超级用户,即管理员的意思!在终端直接输入以下命令即可完成管理员的创建:

C:\Users\AERO\PycharmProjects\djangoProject1>python manage.py createsuperuser
Username (leave blank to use 'aero'): admin
Email address:
Password:
Password (again):
Superuser created successfully.

2.2、登陆功能

在之前手写登陆功能时,我们用POST.get获得用户输入的数据,这时候认证我们面临两个问题:

  1. 表数据如何获取?

  2. 密码如何对比?

2.2.1、用户认证
  1. 该方法自动去auth_user表拿数据。
  2. 自动给用户输入的密码加密后(sha256)再和表中密码的密文进行对比!
from django.contrib import auth  # 必须先导入auth模块


# Create your views here.


def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 必须同时传入账号和密码,不能分开!认证成功后该方法返回为一个用户对象,不匹配则返回None!
        login_result = auth.authenticate(request, username=username, password=password)
        if login_result:  # 有值代表拿到对应的用户对象,即认证成功。
            return HttpResponse('登陆成功')
        else:  # None即不匹配
            return HttpResponse('哪凉快哪待去!')
    return render(request, 'login.html')
2.2.2、保存用户状态

拿到用户对象后,判断当前用户是否存在,在则保存用户状态;只要执行了该方法,你就可以随时随地通过request.user获取到当前登录的用户对象;它是自动去django_session表里面查找对应的用户对象再给你封装到request_user中。

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        login_obj = auth.authenticate(request, username=username, password=password)
        if login_obj:
            auth.login(request, login_obj)  # 类似于request.session[key] = login_obj
            return HttpResponse('登陆成功')
        else:
            return HttpResponse('哪凉快哪待去!')
    return render(request, 'login.html')
2.2.4、判断是否已登录
request.user.authenticated()  # 判断当前用户是否登录,返回布尔值。
2.2.5、查询当前登录用户
request.user

2.3、注销功能

auth.logout(request),没错,就是这么一行代码!

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

2.4、认证功能

在cookie与session的学习中,我们是自己手写认证装饰器,而现在?auth一条龙服务直接端上!!!

2.4.1、局部重定向

装饰器后面跟一个参数可以控制用户未登录重定向的url,登录后自动跳转至用户想要访问的url,这跟我们之前手写装饰器用的return redirect(f'/login/?next={path}')是一样的,利用url传递参数给视图函数!

from django.contrib.auth.decorators import login_required  # 要用装饰器必须先导入此模块

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        login_obj = auth.authenticate(request, username=username, password=password)
        if login_obj:
            auth.login(request, login_obj)
            path = request.GET.get('next')  # 老套路,登录成功后跳转至用户想要访问的url
            if path:
                return redirect(f'{path}')
            else:
                return redirect('/index/')
        else:
            return HttpResponse('哪凉快哪待去!')
    return render(request, 'login.html')


@login_required(login_url='/login/')  # login_url='/login/',检测到用户没有登录则跳转至此页面,可以不写然后自己手动重定向!
def index(request):
    return HttpResponse('我是index页面')
2.4.2、全局重定向

全局重定向是在settings配置文件中添加如下配置:

LOGIN_URL = '/login/'
2.4.3、局部全局对比

全局配置,好处在于毋须重复写代码,缺点是跳转页面固定是一个;而局部就灵活了,可以随意定制,但是要手写参数与指定url!

LOGIN_URL = '/login/',那么局部的就可以删掉了

如果局部和全局都有,听谁的?我说是局部,哪个好?全局好处在于毋须重复写代码,只是跳转页面固定是一个;而局部就灵活了,可以随意定制

2.5、修改密码功能

request.user.set_password()方法,密码先判断两次密码是否一致,再对比旧密码是否正确,密码校验先后顺序不重要!

HTML代码
<body>
    <form action="" method='post'>
        {% csrf_token %}
        <!--因为进入此页面代表一定登录成功。所以直接取值用户名展示出来并用disabled关闭修改,只看不能改!-->
        <p>username:<input type="text" name="username" disabled value="{{ request.user.username }}"></p>
        <p>old_password:<input type="password" name="old_password"></p>
        <p>new_password:<input type="password" name="new_password"></p>
        <p>confirm_password:<input type="password" name="confirm_password"></p>
        <p><input type="submit" value="提交"></p>
    </form>
</body>
views代码
@login_required
def modify_passwd(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        confirm_password = request.POST.get('confirm_password')
        if not new_password == confirm_password:
            return HttpResponse('两次密码输入不一致,请重新输入!')
        if request.user.check_password(old_password):  # 检查密码是否正确
            request.user.set_password(new_password)  # 将新密码保存至内存中
            request.user.save()  # 将内存中的密码写入数据库
            return redirect('/login/')
        else:
            return HttpResponse('密码错误,请重新输入!')
    return render(request, 'modify_passwd.html')

2.6、注册功能

注册就是获取用户输入的数据然后操作auth_user表写入数据,from django.constrib.auth.models import User,User就是auth_user表!

我们也可以像以前操作ORM一样create数据,但是它有个极大的缺陷,密码是明文,我们绝不能用这样的方式!用auth给我们提供的两个方法!

2.6.1、创建普通用户

User.objects.create_user()方法可以创建普通用户

from django.contrib.auth.models import User  # 必须先导入auth_user表


def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        User.objects.create_user(username=username, password=password)
        return redirect('/login/')
    return render(request, 'register.html')
2.6.2、创建超级用户

User.objects.create_superuser(),使用该方法创建超级用户时邮箱必填!不推荐随意创建管理员用户!

def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        User.objects.create_superuser(username=username, password=password, email='123@123.com')
        return redirect('/login/')
    return render(request, 'register.html')

register1

2.7、方法总结

  • 比对用户名和密码是否正确,auth.authenticate(request, username=username, password=password)
  • 保存用户状态,auth.login(request, login_obj)
  • 判断用户是否登录,request.user.authenticated()
  • 获取当前登录用户,request.user.username
  • 校验用户是否登录的装饰器,还有局部和全局的特点,login_required。
  • 修改密码,check_password,set_password,sava。
  • 注销,auth.logout(request)
  • 注册,User.objects.create_user(),User.objects.create_superuser()

三、如何扩展auth_user表

3.1、两个思路:

3.1.1、外键

利用一对一关系建立外键字段就相当于多创建了一张表,但不推荐使用,因为麻烦还涉及联表操作效率低。

3.1.2、面向对象的继承
继承AbstractUser

models里写个类继承AbstractUser,然后在里面写要增加的字段,在第一次用数据库迁移命令时,auth_user表就不会再被创建出来了,而你写的类的创建的表会出现auth_user原本所有的字段加你后面增加的字段。

class UserInfo(AbstractUser):
    phone = models.BigIntegerField()

这么做的好处在于你能够直接点击你自己的表,更加快速地完成操作及扩展,想干嘛就干嘛!

强调:必须是在继承之前没有执行过数据库迁移命令(auth_user没有被创建),如果当前库已经有auth_user了,那么就只能换一个库;继承的类里面不要有和auth_user重复的字段名。

修改配置文件

还需要在配置文件中告诉Django你要用自己的表替代auth_user,AUTH_USER_MODEL = '你的应用名.表名';如果自己写表替代了auth_user,那么auth_user模块的功能还可以照常使用,参考的表也会由原来的auth_user自动变为新表,Django牛皮!!!

AUTH_USER_MODEL = 'study1.UserInfo'

BBS用户表就是上述方式

世间微尘里 独爱茶酒中