Django高级之-Auth

1 Auth模块是什么

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

我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。其实我们在创建好一个django项目之后直接执行数据库迁移命令会自动生成很多表,其中包括django_session表、auth_user表。django在启动之后就可以直接访问admin路由,需要输入用户名和密码,数据参考的就是auth_user表,并且还必须是管理员用户才能进入。

创建超级用户(管理员),控制台输入:

python3 manage.py createsuperuser

# 邮箱可以不写,密码最好8位
# 普通用户不能用命令行创建

这就是django内置的强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。


 

2 auth模块常用方法

from django.contrib import auth

2.1 authenticate()  校验用户名与密码

提供了用户认证功能,即验证用户名以及密码是否正确,一般需要username 、password两个关键字参数。

如果认证成功(用户名和密码正确有效),便会返回一个 User 对象。

authenticate()会在该 User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登录过程中是需要的。

user_obj = auth.authenticate(request,username=username,password=password)  # 括号内必须同时传入用户名和密码
"""
1、自动查找auth_user表
2、自动给密码加密再比对(利用auth_user表创建用户,密码自动存储为密文)
"""
print(user_obj)           # 用户对象,数据不符合则返回None
print(user_obj.username)  # 用户名
print(user_obj.password)  # 密文

2.2 login(HttpRequest, user) 保存用户登录状态

该函数接受一个HttpRequest对象,以及一个经过认证的User对象。该函数实现一个用户登录的功能。

它本质上会在后端为该用户生成相关session数据。通过中间件实现的,因为用户登录后,下次过来浏览器携带随机字符串,自动到django_session表中查找对应的用户对象封装到request.user,之后只要登录了,都能从request.user中拿出登录人的所有信息,所以login方法必须要传request,就是把user_obj塞进去。

from django.contrib import auth
   
def my_view(request):
  username = request.POST['username']
  password = request.POST['password']
  user = auth.authenticate(request,username=username, password=password)
  if user is not None:
    auth.login(request, user)  # 类似于request.session[key] = user_obj,执行了该方法,你就可以在任何地方通过request.user获取到当前登陆的用户对象
    # Redirect to a success page.
    ...
  else:
    # Return an 'invalid login' error message.
    ...
    
def home(request):
    print(request.user)        # 返回登录用户或匿名用户(没有登录的情况下)
    return HttpResponse('ok')

2.3 logout(request) 注销

该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

清空掉request.user里的登录用户对象,所以要传request进去。

from django.contrib import auth

@login_required   # 只有登录用户才能注销
def logout_view(request):
    auth.logout(request)  # 类似于 request.session.flush()
    # Redirect to a success page.

2.4 is_authenticated() 判断当前用户是否登陆

用来判断当前请求是否通过了认证。

def my_view(request):
  if not request.user.is_authenticated():
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

如果没有登录,request.user返回的是匿名用户,并不是None,直接判断如果没有属性会报错,所以才用is_authenticated方法。

2.5 login_requierd() 登录认证装饰器

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

from django.contrib.auth.decorators import login_required
      
@login_required
def my_view(request):
  ...

若用户没有登录,则会跳转到django默认的登录URL, '/accounts/login/?next=/my_view/ ' 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。如果需要自定义登录的URL,比如未登录用户访问,都让它跳转到login页面。

局部配置:未登录用户访问,会跳转到 '/login/?next=/my_view/ ' 登录页面,登录后会重定向到/my_view/路径。

from django.contrib.auth.decorators import login_required
      
@login_required(login_url='/login/')  
def my_view(request):
  ...

全局配置:在settings.py文件中通过LOGIN_URL进行修改。

LOGIN_URL = '/login/'  # 这里配置成你项目登录页面的路由

全局的好处在于无需重复写代码,但是跳转的页面却很单一。局部的好处在于不同的视图函数在用户没有登陆的情况下可以跳转到不同的页面,优先级局部高于全局。

2.6 set_password(password) 与  check_password(password)

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

auth 提供的一个修改密码的方法set_password,接收要设置的新密码作为参数。注意:设置完一定要调用用户对象的save方法!!!

@login_required  # 修改密码必须为登录用户
def set_password(request):
    err_msg = ''
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        repeat_password = request.POST.get('repeat_password')
        # 检查旧密码是否正确 自己加密对比密码,正确返回True,错误返回False
        if request.user.check_password(old_password):  
            if not new_password:
                err_msg = '新密码不能为空'
            elif new_password != repeat_password:
                err_msg = '两次密码不一致'
            else:
                request.user.set_password(new_password)    # 仅仅是在修改对象的属性
                request.user.save()                        # 这一步才是真正的操作数据库
                return redirect("/login/")
        else:
            err_msg = '原密码输入错误'
    content = {
        'err_msg': err_msg,
    }
    return render(request, 'set_password.html', locals()) # 把request和content传到前端,前端可以展示request.user以及错误信息

2.7 create_user() 与 create_superuser()

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

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

user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)
# user = User.objects.create(username=username,password=password)  auth_user表写入数据,不能用create,密码没有加密处理

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

from django.contrib.auth.models import User

# 使用代码创建超级用户 邮箱是必填的 而用命令创建则可以不填
user = User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...)

注册功能:

from django.contrib.auth.models import User
from django.http import render, redirect

def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 操作auth_user表写入数据
        User.objects.create_user(username=username, password=password)                          #创建普通用户
        User.objects.create_superuser(username=username, password=password, email='123@qq.com') #创建超级用户
        return redirect('/login/')
    return render(request, 'register.html')

2.8 User对象的属性

获取当前用户 request.user, 返回登录用户或匿名用户,通过 is_authenticated() 方法判断是登录用户还是匿名用户。

User对象属性:username, password

is_staff : 用户是否拥有网站的管理权限,是否是超级用户。

is_active : 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。比如登录时输错3次密码,改为false,在不删除用户的前提下禁止该用户登录。


 

3 扩展默认的auth_user表

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

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

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

我们可以通过继承内置的 AbstractUser 类,来定义一个自己的Model类。这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。

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

如果继承了AbstractUser类,那么在执行数据库迁移命令的时候,auth_user表就不会再创建出来了,而UserInfo表中会出现auth_user表所有的字段外加自己扩展的字段,这么做的好处在于你能够直接点击你自己的表更加快速的完成操作及扩展。

替换auth_user表的前提:

1.在继承之前没有执行过数据库迁移命令(一旦执行数据库迁移命令,auth_user表就会创建出来)
    auth_user表没有被创建,如果当前库已经创建了那么你就重新换一个库
    
2.继承的类里面不要覆盖AbstractUser里面的字段名
    auth_user表里面有的字段都不要动,只扩展额外字段即可
    
3.需要在配置文件中告诉django你要用UserInfo替代auth_user(******)
AUTH_USER_MODEL = 'app01.UserInfo'   # '应用名.表名'

再次注意:

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

 

posted @ 2023-01-01 20:20  不会钓鱼的猫  阅读(129)  评论(0编辑  收藏  举报