Django 用户认证组件和messages消息组件
用户认证组件
Django默认已经提供了认证系统Auth模块,我们认证的时候,会使用auth模块里面给我们提供的表。认证系统包含:
- 用户管理
- 权限
- 用户组
- 密码哈希系统
- 用户登录或内容显示的表单和视图
- 一个可插拔的后台系统 admin
A用户登录后再用同一个客户端登录B用户,session在数据库的记录会被新建且覆盖之前的session,从始至终只有1条数据库记录 而A用户登完,再用A用户账号密码登陆,原始的session在数据库的记录不会发生变化.
前提: 数据库为auth-user表,创建超级用户 python manage.py createsuperuser
(1)Django用户模型类
Django认证系统中提供了用户模型类User保存用户的数据,默认的User包含以下常见的基本字段:
字段名 | 字段描述 |
---|---|
username |
必选。150个字符以内。 用户名可能包含字母数字,_ ,@ ,+ . 和- 个字符。 |
first_name |
可选(blank=True )。 少于等于30个字符。 |
last_name |
可选(blank=True )。 少于等于30个字符。 |
email |
可选(blank=True )。 邮箱地址。 |
password |
必选。 密码的哈希加密串。 (Django 不保存原始密码)。 原始密码可以无限长而且可以包含任意字符。 |
is_staff |
布尔值。 设置用户是否可以访问Admin 站点。 |
is_active |
布尔值。 指示用户的账号是否激活。 它不是用来控制用户是否能够登录,而是描述一种帐号的使用状态。 |
is_superuser |
是否是超级用户。超级用户具有所有权限。 |
last_login |
用户最后一次登录的时间。 |
date_joined |
账户创建的时间。 当账号创建时,默认设置为当前的date/time。 |
上面缺少一些字段,所以后面我们会对当前内置的用户模型进行改造,比如说它里面没有手机号字段,后面我们需要加上。
(2)Auth模块内置方法介绍
from django.contrib import auth
内置方法名称 | 说明 |
---|---|
authenticate(username, password) | 用于用户认证。将输入的密码转为密文去认证,认证成功返回用户对象,失败则返回None |
login(HttpRequest, user) | 用于用户登录。user参数是经过认证的User对象。登录成功后将用户身份信息记录到请求的会话对象中存储。后台使用request.user可获取当前登录的用户对象。如果未登录成功,则request.user得到的是一个匿名用户对象。 |
logout(request) | 清除当前请求,注销会话等同于做了session.flush(),但是会清除所有的session_data,如果有其他的用户数据要使用,建议使用del request.session["log_in"],删除部分字段,对其他字段的内容不做影响 |
(2.1)User模块内置方法介绍
from django.contrib.auth.models import User
注意如果User对象被继承了,则用继承的对象
内置方法名称 | 说明 |
---|---|
is_authenticated | 判断当前用户是否经过认证 |
is_anonymous | 判断当前用户是否是匿名用户 |
create_user() | 创建新用户,至少提供用户名和密码 创建的密码会加密 |
create() | create是models下的方法,放在这里比较只是展示他创建的密码是明文的 供参考了解! |
set_password(password) | 修改密码 设置用户的密码为给定的原始字符串,并负责密码的。 不会保存User对象。当None为raw_password时,密码将设置为一个不可用的密码。 |
check_password(password) | 检查密码是否正确 如果给定的password是用户的真实密码,则返回True,可以在校验用户密码时使用。 |
详细看官方文档 https://docs.djangoproject.com/zh-hans/3.2/ref/contrib/auth/
(3)内置方法代码示例
user = auth.authenticate(request,username=username,password=password)
if user:
auth.login(request,user) # 这一步会把认证的用户_id写入到django_session表中,产生一个session_key,后续再中间件中可以通过session_key获取对应加密的session信息,实现后续的cookie认证,权限认证等功能.
# auth.login的主要功能就是实现了requests.session["user_id"]=user.id 把登录的user对象写入到session中去
return redirect("/home/page")
(4)auth认证不通过后的装饰器模块
django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()
在setting.py要设置login_url,设置登陆页面,一旦装饰器认证失败返回这个登陆页面
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
(5) )request.user
Django有一个默认中间件,叫做AuthenticationMiddleware,每次请求进来都会去session中去一个userid,取不到的话,赋值request.user = AnonymousUser() , 一个匿名用户对象。
当用户组件auth.login一旦执行,将userid到session中后,再有请求进入Django,将注册的userid对应的user对象赋值给request.user,即再后面的任何视图函数中都可以从request.user中取到该客户端的登录对象。
匿名用户还有下面其他几个属性可以用
id 永远为None
username 永远为空字符串
get_username() 永远返回空字符串
is_staff和is_superuser 永远为false
is_active 永远为false
groups 和user_permission 永远为空
is_annoymous() 返回True
is_authenticated 返回False
set_password(),check_password(),save()和delete()会引发NotImplementError
(6) 自定义用户表
from django.contrib.auth.models import AbstractUser
设置Auth认证模块使用的用户模型为我们自己定义的用户模型
格式:“子应用目录名.模型类名”
AUTH_USER_MODEL = 'users.User'
from django.contrib.auth.models import User,AbstractUser
'''
这里AbstractUser 父类就已经有了username password等一些列的字段了,
其他的只是我们扩展的字段而已
'''
class UserInfo(AbstractUser):
nid = models.AutoField(primary_key=True)
telphone = models.CharField(max_length=11, null=True, unique=True)
avatar = models.FileField(upload_to="avatars/", default="avatars/default.png")
create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
blog = models.OneToOneField(to="Blog", to_field="nid", null=True,on_delete=models.CASCADE)
def __str__(self):
return self.username
(7) auth中间件功能简介
'django.contrib.auth.middleware.AuthenticationMiddleware'中间件实现的功能
1. user_id = request.session.get("user_id") # 从session表的user_id字段获取用户id
2. from djang.contrib.auth.models import User
user = User.object.get(pk=user_id) # 然后通过用户id和User表获取用户对象
if user:
request.user=user # 把用户对象赋值给request.user
else:
request.user=AnonymousUser() # 把匿名用户对象赋值给request.user
消息组件
在网页应用中,我们经常需要在处理完表单或其它类型的用户输入后,显示一个一次性的通知信息给用户。
对于这个需求,Django提供了基于Cookie或者会话的消息框架messages,无论是匿名用户还是认证的用户。这个消息框架允许你临时将消息存储在请求中,并在接下来的请求(通常就是下一个请求)中提取它们并显示。每个消息都带有一个特定的level标签,表示其优先级(例如info、 warning或error)。
还可以利用这个一次性的消息实现跳转需求
- 进入页面点击删除按钮
- 跳转到某个实例详情页面后进行二次确认是否删除,点击确认后进行删除
- 再调回到第一步的页面
消息组件的配置
在settings.py中有4处配置
1. 启动messages应用
INSTALLED_APPS = [
'django.contrib.messages',
]
2. messages框架默认使用的存储后端为sessions。所以Session中间件必须被启用,并出现在Message中间件之前。
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
]
3.TEMPLATES设置中的DjangoTemplates选项包含的'context_processors'配置项要包含'django.contrib.messages.context_processors.messages'。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
4.MESSAGE_STORAGE默认值是FallbackStorage,是同时会存储在session和cookie,也可以按照需求自行更改
MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'
django.contrib.messages.storage.cookie.CookieStorage
django.contrib.messages.storage.session.SessionStorage
消息组件的导入和常用方法
from django.contrib import messages
add_message(request, level, message, extra_tags='', fail_silently=False)[source]
新增一条消息:
from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')
提供请求对象request(直接用就行),消息级别、消息内容字符串三个参数即可。
或者使用下面的快捷方式
messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')
在自定义消息级别时,应小心避免覆盖现有级别。内置级别的值为:
级别 对应整数值
DEBUG 10
INFO 20
SUCCESS 25
WARNING 30
ERROR 40
get_messages(request)[source]
messages可以在视图中用代码获取,也可以在html模版文件获取
messages是一个列表,必须用for标签循环它;
即使你知道只有一条消息,也要迭代messages列表,否则下个请求中,上个请求的消息不会被清除。
对于每一个消息实例,都包含下面的属性,可以在模版或视图中调用:
message: 消息的实际内容文本。不要使用message.message,直接message。
level: 消息级别,一个整数。
tags: 一个字符串,由该消息的所有标签(extra_tags和tags)组合而成,组合时用空格分割开这些标签。
extra_tags: 一个字符串,由该消息的定制标签组合而成,并用空格分割。默认为空。
level_tag: 当前消息级别对应的CSS字符串,前面介绍过。
在你的模板文件中,像下面这样使用:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
相关说明:
通过if判断是否有消息;
可以通过message.tags拿到每个消息的CSS样式
消息过期机制
默认情况下,如果包含消息的迭代器完成迭代后,当前请求中的消息都将被删除。
如果你不想这么做,想保留这些消息,那么需要显式的指定used参数为False,如下所示:
storage = messages.get_messages(request)
for message in storage:
do_something_with(message)
storage.used = False
set_level(request, messages.DEBUG)
messages.set_level(request, messages.DEBUG)
messages.debug(request, 'Test message...')
在另外一个视图中修改最小级别为WARNING
messages.set_level(request, messages.WARNING)
messages.success(request, 'Your profile was updated.') # 被忽略,不记录
案例实现
利用这个一次性的消息实现跳转需求
- 进入页面点击删除按钮
- 跳转到某个实例详情页面后进行二次确认是否删除,点击确认后进行删除
- 再调回到第一步的页面