一、Auth是什么?
Auth模块是django自带的用户认证模块。
它内置了强大的用户认证系统——auth(from django.contrib import auth)
它默认使用auth_user表来存储用户数据
二、走近Auth(常用方法)
authenticate()
提供了用户认证功能,即验证用户名以及密码是否正确,一般需要username 、password两个关键字参数。
如果认证成功(用户名和密码正确有效),便会返回一个 User 对象。
authenticate()会在该 User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登录过程中是需要的。
用法:
user = authenticate(username='usernamer',password='password')
login(HttpRequest, user)
该函数接受一个HttpRequest对象,以及一个经过认证的User对象。
该函数实现一个用户登录的功能。它本质上会在后端为该用户生成相关session数据。
下面通过一个登录的函数来试试:
auth模块默认用auth_user表来存储用户数据:
命令行创建一个超级用户(在Tools里的run manage.py Task):createsuperuser
可以看到,默认的密码是加密的。
写一个登录的视图函数:
def auth_login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') '''之前我们要先查,然后比对,现在试试auth模块的authenticate()方法 models.User.objects.filter(username=username,password=password).first()''' user_obj = auth.authenticate(request, username=username, password=password) if user_obj: '''记录用户状态,之前我们用的是request.session["name"] = "shj"''' auth.login(request, user_obj) # 一旦登录了,可以在任何地方,通过request.user获取到当前登录的对象 return HttpResponse('ok') return render(request, 'auth_login.html')
is_authenticated()
用来判断当前请求是否通过了认证。
def auth_index(request): print(request.user.is_authenticated()) # 判断当前用户是否已经登录 print(request.user, type(request.user)) # AnonymousUser <class 'django.utils.functional.SimpleLazyObject'> # 没有登录时,显示我是游客身份 # 登录后就是我注册的admin return HttpResponse('ok')
logout(request)
该函数接受一个HttpRequest对象,无返回值。
当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
def auth_logout(request): auth.logout(request) # 相当于request.session.flush() return HttpResponse('ok')
User对象:
from django.contrib.auth.models import User
User实质上是默认的用户表。
User对象属性:username, password
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。
- User.objects.create(username=username,password=password) # 不能再用create创建,它创建的密码是明文的
- User.objects.create_user(username=username,password=password) # 创建普通用户
- User.objects.create_superuser(username=username,password=password,email='123@163.com') # 创建超级用户
创建超级用户需要一个email字段是必填的。
下面来写一个注册示例:
def auth_register(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 只需通过用户名查询用户是否已存在(如果是自己建的表),如果是默认的表,用户名和密码都得传 user_obj = auth.authenticate(request, username=username) if user_obj: return HttpResponse('当前用户已存在') User.objects.create_user(username=username, password=password) return render(request, 'auth_register.html')
auth_register.html
<form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>password:<input type="password" name="password"></p> <input type="submit"> </form>
从表中看到,注册成功后,因为我用的是创建普通用户,所以is_superuser字段为0,自然也没有网站管理权限,因此is_staff也为0,没有登录过,所以last_login为空。后面的date_joined时间为UTC标准时间,比中国时间慢8H。
check_password(password)
auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。
密码正确返回True,否则返回False。
set_password(password)
auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。
注意:设置完一定要调用用户对象的save方法!!!
写一个修改密码的示例:
def set_password(request): user = request.user 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', '') # 检查旧密码是否正确 if user.check_password(old_password): if not new_password: err_msg = '新密码不能为空' elif new_password != repeat_password: err_msg = '两次密码不一致' else: user.set_password(new_password) # 设置新密码 user.save() # 修改完后一定要保存,否则更改就无效了 return redirect("/login/") else: err_msg = '原密码输入错误' content = { 'err_msg': err_msg, } return render(request, 'set_password.html', content)
login_requierd()
auth 给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验。
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import login_required @login_required def auth_home(request): return HttpResponse('我是home页面,登录才能访问') @login_required def auth_xxx(request): return HttpResponse('我是xxx页面,登录才能访问')
若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
如果是自定义的url,那么直接访问auth_home和auth_xxx会报错。
要解决这个问题,有两种方式:
- 局部配置:@login_required(login_url='/auth_login/')——即在装饰器指定跳转的login的路径
- 到配置文件进行全局配置
通过上面也可以看到,如果我们访问的页面需要登录,那么在跳转到登录页面时,会在路径后拼接我原来要访问的路径:
那么后续可以通过request.GET.get('next')可以拿到原来的路径,然后等登录成功后,我们可以通过代码重定向到用户本来要访问的网页。
三、AbstractUser扩展默认的auth_user表
内置的认证系统虽然好用,但是auth_user表字段都是固定的那几个,我在项目中没法拿来直接使用啊!
别着急!人家当然考虑到这点了!
通过继承内置的 AbstractUser 类,来定义一个自己的Model类。这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。
首先得到配置文件修改默认的表:
# 告诉django不再使用默认的auth_user,而使用我们自己定义的表
# AUTH_USER_MODEL = "app名.models里面对应的模型表名"
AUTH_USER_MODEL = 'app01.Userinfo'
然后建表,并执行数据库迁移命令:
from django.db import models
from django.contrib.auth.models import User, AbstractUser
class Userinfo(AbstractUser):
phone = models.CharField(max_length=32)
avatar = models.CharField(max_length=32)
之后到数据库中看一眼,发现已经没有auth_user表了, 我们创建的表替代了它,并且最后也有了我们自己定义的字段。
四、 AbstractBaseUser扩展auth_user表
上面讲了AbstractUser,看源码得知AbstractUser是继承了AbstractBaseUser。
如果还觉得AbstractUser帮我们建了太多的字段,那么可以考虑使用以下AbstractBaseUser。它大概和上面的AbstractUser配置一样。
建表:models.py
创建后的所有表字段:可以看到,django只是帮我们新建了id,password,last_login三个字段而已。
在模型类中我们必须定义一个用户名字段,并指定属性为unique,然后告诉django这个字段是用户名字段:
username = models.CharField(max_length=32,unique=True) USERNAME_FIELD = 'username' # 这当中的username你可以任意命名,unique必须指定为True
如果不写这两句话,你会发现执行数据库迁移命令怎么创建表都没办法创建出来,一直报错:
AttributeError: type object 'UserInfo' has no attribute 'USERNAME_FIELD'