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)。
还可以利用这个一次性的消息实现跳转需求

  1. 进入页面点击删除按钮
  2. 跳转到某个实例详情页面后进行二次确认是否删除,点击确认后进行删除
  3. 再调回到第一步的页面

消息组件的配置

在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.') # 被忽略,不记录

案例实现

利用这个一次性的消息实现跳转需求

  1. 进入页面点击删除按钮
  2. 跳转到某个实例详情页面后进行二次确认是否删除,点击确认后进行删除
  3. 再调回到第一步的页面
posted @ 2021-09-29 14:17  零哭谷  阅读(121)  评论(0编辑  收藏  举报