Python进阶35-Django Auth组件

2022-09-26 13:51:54 浏览数 (1)

  • 什么是Auth模块
  • auth模块用法
  • Auth模块功能详解
  • 扩展默认的auth_user表

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


什么是Auth模块


介绍

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

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

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

auth模块用法


创建项目

数据库迁移

代码语言:javascript复制
MacBook-pro:auth_module driverzeng$ python3 manage.py makemigrations
MacBook-pro:auth_module driverzeng$ python3 manage.py migrate

这个表里的用户,不能直接往里面写,得使用命令,还是运行manage.py

代码语言:javascript复制
# 创建超级用户
MacBook-pro:auth_module driverzeng$ python3 manage.py createsuperuser


模板层

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <div>
        <lable>用户:<input type="text" name="name"></lable>
    </div>
    <div>
        <lable>密码:<input type="text" name="pwd"></lable>
    </div>
    <input type="submit" value="登录">
</form>
</body>
</html>

视图层

代码语言:javascript复制
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from django.contrib import auth
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        user = auth.authenticate(request,username=name,password=pwd)
        ## 相当于:user = models.User.objects.filter(name=name,pwd=pwd).first()
        if user:
            return HttpResponse('登录成功')
        else:
            return HttpResponse('用户名或密码错误')

路由层

代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
]

Auth模块功能详解


登录

代码语言:javascript复制
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from django.contrib import auth
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        user = auth.authenticate(request,username=name,password=pwd)
        ## 相当于:user = models.User.objects.filter(name=name,pwd=pwd).first()
        if user:
            # 登录,其实就是把用户的信息放到session中
            auth.login(request,user)
            ## 之前是这样 request.session['name'] = name
            return HttpResponse('登录成功')
        else:
            return HttpResponse('用户名或密码错误')


取出当前登陆用户

只要登录成功,之后在任意视图,都可以取出该用户,这个功能太强大了,省了我们很多事

代码语言:javascript复制
def test(request):
    user=request.user
    print(user)
    return HttpResponse('当前登录的用户:%s' % user)
代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
]

如果没有登录就会是一个匿名用户:AnonymousUser


注销

代码语言:javascript复制
def user_logout(request):
    auth.logout(request)
    user = request.user
    return HttpResponse('注销 [%s] 成功' %user)
代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
    url(r'^user_logout/', views.user_logout),
]


登录认证装饰器

目前 我有个test页面,不管用户有没有登录都可以访问,因为没有登录的时候,可以用匿名用户访问,Django内置了一个登录认证的装饰器,如果没有登录,或者是匿名用户,可以跳转到指定的页面

模板层

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
    <meta charset="UTF-8">
    <title>个人中心</title>
</head>
<body>
当前登录用户:{{ user }}
<div>
    <a href="/user_logout/">点我注销</a>
</div>
</body>
</html>

视图层

代码语言:javascript复制
from django.shortcuts import render, HttpResponse, redirect
from django.contrib.auth.decorators import login_required
# Create your views here.
from django.contrib import auth


def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        user = auth.authenticate(request, username=name, password=pwd)
        ## 相当于:user = models.User.objects.filter(name=name,pwd=pwd).first()
        if user:
            # 登录,其实就是把用户的信息放到session中
            auth.login(request, user)
            ## 之前是这样 request.session['name'] = name
            return redirect('test')
        else:
            return HttpResponse('用户名或密码错误')


@login_required(redirect_field_name='zls', login_url='/login/')
def test(request):
    user = request.user
    print(user)
    return render(request,'test.html',locals())


def user_logout(request):
    user = request.user
    auth.logout(request)
    return redirect('/login/')

路由层

代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
    url(r'^user_logout/', views.user_logout),
]

代码语言:javascript复制
## 导入装饰器:from django.contrib.auth.decorators import login_required
## redirect_field_name 修改url的?后面传递的参数
## login_url 如果没有登录,跳转到页面

但是如果装饰器需要传递参数,如果有一万个视图函数,我就要传递一万次参数?很麻烦,所以Django帮我们做了一件事,settings文件中,修改即可。

代码语言:javascript复制
LOGIN_URL = '/login/'
代码语言:javascript复制
from django.shortcuts import render, HttpResponse, redirect
from django.contrib.auth.decorators import login_required
# Create your views here.
from django.contrib import auth


def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        user = auth.authenticate(request, username=name, password=pwd)
        ## 相当于:user = models.User.objects.filter(name=name,pwd=pwd).first()
        if user:
            # 登录,其实就是把用户的信息放到session中
            auth.login(request, user)
            ## 之前是这样 request.session['name'] = name
            return redirect('/test/')
        else:
            return HttpResponse('用户名或密码错误')


@login_required()
def test(request):
    user = request.user
    print(user)
    return render(request,'test.html',locals())


def user_logout(request):
    user = request.user
    auth.logout(request)
    return redirect('/login/')

用户注册

代码语言:javascript复制
from django.shortcuts import render, HttpResponse, redirect
from django.contrib.auth.decorators import login_required
# Create your views here.
from django.contrib import auth

def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        user = auth.authenticate(request, username=name, password=pwd)
        ## 相当于:user = models.User.objects.filter(name=name,pwd=pwd).first()
        if user:
            # 登录,其实就是把用户的信息放到session中
            auth.login(request, user)
            ## 之前是这样 request.session['name'] = name
            return redirect('/test/')
        else:
            return HttpResponse('用户名或密码错误')


@login_required()
def test(request):
    user = request.user
    print(user)
    return render(request,'test.html',locals())


def user_logout(request):
    user = request.user
    auth.logout(request)
    return redirect('/login/')

from django.contrib.auth.models import User

def register(request):
    name='cls'
    pwd='123'
    ## 不能这么创建:密码不能是明文的
    ## user = User.objects.create(username=name,password=pwd)

    ## 创建超级用户
    #user = User.objects.create_superuser(username=name,password=pwd)
    ## 创建普通用户
    user = User.objects.create_user(username=name,password=pwd)
    return HttpResponse('用户:%s 注册成功' %user)
代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
    url(r'^user_logout/', views.user_logout),
    url(r'^register/', views.register),
]


校验密码

因为密码是加密的,所以我们不能直接拿出来,还得用Django给我们写的方法。

代码语言:javascript复制
def check_pwd(request):
    pwd = '123'
    res = request.user.check_password(pwd)
    print(res)
    if res:
        return HttpResponse('密码校验成功')
    else:
        return HttpResponse('密码校验失败')
代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
    url(r'^user_logout/', views.user_logout),
    url(r'^register/', views.register),
    url(r'^check_pwd/', views.check_pwd),
]

zls用户的密码是:zls12345

代码语言:javascript复制
def check_pwd(request):
    pwd = 'zls12345'
    res = request.user.check_password(pwd)
    print(res)
    if res:
        return HttpResponse('密码校验成功')
    else:
        return HttpResponse('密码校验失败')


修改密码

代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
    url(r'^user_logout/', views.user_logout),
    url(r'^register/', views.register),
    url(r'^check_pwd/', views.check_pwd),
    url(r'^set_pwd/', views.set_pwd),
]
代码语言:javascript复制
def set_pwd(request):
    pwd = 'zls111'
    user = request.user
    user.set_password(pwd)
    user.save()
    return HttpResponse('OK')

注意:修改密码一定要 调用save方法,否则不保存。


是否认证通过

代码语言:javascript复制
def auth_1(request):
    res = request.user.is_authenticated
    print(res)
    
    if res:
        return HttpResponse('认证成功')
    else:
        return HttpResponse('认证失败')
代码语言:javascript复制
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^test/', views.test),
    url(r'^user_logout/', views.user_logout),
    url(r'^register/', views.register),
    url(r'^check_pwd/', views.check_pwd),
    url(r'^set_pwd/', views.set_pwd),
    url(r'^auth_1/', views.auth_1),
]

该方法,主要不是在视图使用,是在模板中使用。


封号和后台管理

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

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

扩展默认的auth_user表

这内置的认证系统这么好用,但是auth_user表字段都是固定的那几个,我在项目中没法拿来直接使用啊!

比如,我想要加一个存储用户手机号的字段,怎么办?

聪明的你可能会想到新建另外一张表然后通过一对一和内置的auth_user表关联,这样虽然能满足要求但是有没有更好的实现方式呢?

答案是当然有了。

我们可以通过继承内置的 AbstractUser 类,来定义一个自己的Model类。

这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。

两种方式,复用User表


一对一关联auth_user表

代码语言:javascript复制
from django.db import models

# Create your models here.
from django.contrib.auth.models import User
class UserDetail(models.Model):
    phone = models.CharField(max_length=32)

    # 如果是从外部引入的表模型是不能加 引号的
    #user = models.OneToOneField(to='User')
    user = models.OneToOneField(to=User)

数据库迁移

代码语言:javascript复制
MacBook-pro:~ driverzeng$ cd /Users/driverzeng/PycharmProjects/auth_module
MacBook-pro:auth_module driverzeng$ python3 manage.py makemigrations
MacBook-pro:auth_module driverzeng$ python3 manage.py migrate


定义表模型继承

代码语言:javascript复制
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
    """
    用户信息表
    """
    nid = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=11, null=True, unique=True)
    
    def __str__(self):
        return self.username

注意:

按上面的方式扩展了内置的auth_user表之后,一定要在settings.py中告诉Django,我现在使用我新定义的UserInfo表来做用户认证。写法如下:

代码语言:javascript复制
# 引用Django自带的User表,继承使用时需要设置
AUTH_USER_MODEL = "app01.UserInfo"

再次注意:

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

0 人点赞