Django 16 Django进阶-auth中间件

Django 16 Django进阶-auth中间件

回顾自行编写的认证登录 一个基于用户的网站免不了要实现用户认证,用户状态等各种功能.可以自行编写模块,但是Django内建了可以用于用户相关功能的auth模块,来看一看auth模块的API. 在之前学习session的过程中,是用session加装饰器来控制访问index页面的. 为了知道是哪个用户

回顾自行编写的认证登录

一个基于用户的网站免不了要实现用户认证,用户状态等各种功能.可以自行编写模块,但是Django内建了可以用于用户相关功能的auth模块,来看一看auth模块的API. 在之前学习session的过程中,是用session加装饰器来控制访问index页面的. 为了知道是哪个用户登录,在session中保存了一段信息用于了解用户是谁,如果要显示用户的信息,还可以在session中存入用户名等信息. 将更改过的自行编写的登陆代码展示如下:
# views.py
from django.shortcuts import render, HttpResponse, redirect
from django.contrib import auth
from authfuc import models
from functools import wraps


def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        if request.session.get('is_login') == 1:
            ret = func(request, *args, **kwargs)
            return ret
        else:
            return render(request, 'login.html', {"warning": "请登录"})

    return inner


def login(request):
    if request.method == "GET":
        return render(request, 'login.html')
    else:
        user = request.POST.get("username", None)
        pwd = request.POST.get("password", None)

        if user:
            user_db = models.User.objects.filter(username=user, password=pwd)
            if user_db:
                request.session['is_login'] = 1
                request.session['name'] = user
                return redirect("/index/")

        return render(request, 'login.html', {"warning": "用户名或密码错误"})


@check_login
def index(request):
    if request.method == "GET":
        user = request.session.get("name","")
        return render(request, "index.html", {"user_name":user})
    else:
        request.session.flush()
        return redirect("/login/")
页面如下:
<div class="container">
    <div class="col-sm-6 col-sm-push-3">
        <form action="/login/" method="post">
            <h1 class="text-center">请登录</h1>
            {% csrf_token %}
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" id="username" name="username" class="form-control">
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" id="password" name="password" class="form-control">
            </div>
            <div class="form-group">
                <p class="text-center text-danger">{{ warning }}</p>
            </div>
            <div class="form-group">
                <div class="col-sm-4 col-sm-push-4 ">
                    <button type="submit" class="btn btn-primary col-center-block">登录</button>
                </div>

            </div>
        </form>
    </div>
</div>
auth中间件写在settings.py的中间件里,是如下的配置:
MIDDLEWARE = [
     'django.contrib.auth.middleware.AuthenticationMiddleware',
]
auth中间件的作用,也就是自动在request里边帮我们加上和用户相关的信息,我们就不用再自行编写往session或者向其他传输内容中增添用户信息的方法.需要用到用户验证的时候,只需要从request里边取出用户信息并且操作即可.

auth中间件的使用方法

建立超级用户

使用系统的中间件就不会使用我们之前自己创建的表和编写的视图了.要使用auth的功能,需要先通过manage.py创建超级用户:
python manage.py createsuperuser
会弹出来交互信息,先要输入用户名,如果为空默认是administrator.然后输入邮箱,可以不填,再输入两次密码确认,即可成功创建用户. 之后,在auth_user表内即可看到新增的用户.

auth.authenticate验证用户名和密码

然后以此用户来重写login函数:
def login(request):
    if request.method == "POST":
        # 用auth判断用户
        username = request.POST.get("username", None)
        pwd = request.POST.get("password", None)
        user = auth.authenticate(username=username, password=pwd)
        print(username,pwd,user)
        if user:
            return redirect("/index/")

    return render(request,"login.html")
这里利用到auth.authenticate方法,即按照POST的用户名和密码,到auth_user表内取用户对象.如果成功,则user不会为空,如果没有找到匹配对象,则user返回None.后边判断一下user即可.

附加用户状态

现在是一个纯粹的验证,还没有任何附加用户的信息,想要在用户完成认证之后保存用户状态,需要用到login(HttpRequest, user)函数. 这个函数是调用了Django的session中间件进行操作,所以在中间件注册的时候,auth模块是放在session模块下边的.
def login(request):
    if request.method == "POST":
        # 用auth判断用户
        username = request.POST.get("username", None)
        pwd = request.POST.get("password", None)
        user = auth.authenticate(username=username, password=pwd)
        if user:
            # 通过session模块把登录成功的用户封装到request.user对象里
            auth.login(request, user)
            return redirect("/index/")
    return render(request, "login.html")
通过auth.authenticate方法验证用户,如果通过,则调用auth.login,会将user对象附加到request上边,之后在其他视图函数中可以操作request.user

使用request.user对象和logout清除登陆信息

def index(request):
    if request.method == "GET":
        # 判断用户是否经过认证
        if request.user.is_authenticated():
            return render(request, "index.html", {"user_name": request.user.username})
    # 清除所有登陆信息
    auth.logout(request)
    return redirect('/login/')
如果没有经过验证,直接调用request.user得到的是一个匿名用户对象.用is_authenticated()可以验证当前request里的用户是否已经登录.如果需要注销,用auth.logout来清除当前request里的全部登录信息.

login_requierd装饰器

上边已经用auth模块在视图函数内编写了验证,登录,使用登录信息,退出登录的功能. auth模块还提供了便利的装饰器给视图使用. 新写一个简单的视图,然后加上装饰器,就实现了验证功能.
from django.contrib.auth.decorators import login_required
@login_required
def index2(request):
    return render(request, "index2.html")
访问/index2/的时候若用户没有登录,则会跳转到Django默认的登录URL '/accounts/login/' 并通过GET方法附加?next=当前路径来传递访问前页面.这样可以用登陆页面视图函数将之前的路径拿到埋在登陆页面里,然后实现跳转回原来页面的功能. 如果要更改Django的默认登陆URL,需要在settings.py里配置LOGIN_URL = "/login/". auth模块的使用方法主要就是自行编写和使用装饰器两种方法,设置都比较简单.今后就多使用Django的登陆模块.

auth 用户操作

用户操作主要是对auth_user表的操作,其实也就是通过auth对ORM进行操作.

新增普通用户 create_user()

实际上就是通过ORM对auth_user表进行操作:
from django.contrib.auth.models import User
# 将用户注册表单的信息传递给ORM
user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)

新增超级用户 create_superuser()

与建立普通用户的方法不同,采用create_superuser方法.
from django.contrib.auth.models import User
user = User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...)

验证密码 check_password(password)

验证密码需要对一个user对象进行操作.
# ret is a boolean type
ret = request.user.check_password(pwd_str)
单独验证密码经常用在用户单独修改密码的场景,属于比较常用的方法.

设置密码 set_password(password)

# 修改密码后必须调用.save()方法,否则不生效
user.set_password(password='')
user.save()

user 其他属性

is_staff : 布尔值,返回是否是网站管理权限 is_active : 是否允许用户登录,在不删除用户的情况下阻止登录.

扩展用户数据

目前所有的用户使用的都是Django系统自动生成的auth_user表,其中的字段也是固定好的. 如果在用户注册的时候或者其他场景需要收集更多的用户数据,可以对该表进行扩展. 扩展的方法是自定义一个继承用户表类的新类,然后在settings.py里指定该表.
# 导入auth的ORM里的用户表基类
from django.contrib.auth.models import AbstractUser

#新建一个表继承这个基类,不用再继承models.Model
class UserInfo(AbstractUser):
    nid = models.AutoField(primary_key=True)
    username = ....
    password = ....
    custom_field1 = ...
    custom_field2 = ...

    def __str__(self):
        return self.username

# settings.py中在注册app的配置以下的部分新增自定义验证表
AUTH_USER_MODEL = "app名.UserInfo"
LICENSED UNDER CC BY-NC-SA 4.0
Comment