用户认证组件
2.示例学习:用户认证、登录(全局request.user)、匿名用户、注册、注销、认证装饰器(next)...
项目文件/settings.py
数据库 略!
LOGIN_URL = "/login/"
项目文件/urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('login/', views.login),
path('index/', views.index),
path('logout/', views.logout),
path('reg/', views.reg),
path('order/', views.order),
]
app01.views.py
from django.shortcuts import render,HttpResponse,redirect
# 导入auth模块
from django.contrib import auth
# 对应数据库迁移django自带的 auth_user表的 对象
from django.contrib.auth.models import User
# 登录装饰器
# 在setting.py 配置 LOGIN_URL = "/login/"
# 如果没有登录就访问index路径,就会跳转到/login/页面
# 必须配置,否则将会跳转到默认的一个不相干的路径
from django.contrib.auth.decorators import login_required
def login(request):
if request.method == "POST":
username = request.POST.get("user")
pwd = request.POST.get("pwd")
"""auth.authenticate()
提供了用户认证,即验证用户名以及密码是否正确,一般需要username password两个关键字参数
如果认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性
标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数
据库中直接取出来不经过authenticate()的User对象会报错的!!
使用用户组件更严谨,比如同一个浏览器登录不同的用户,对应
的session信息 django_session表中的session_key就会跟换,
而直接用session操作只替换session_data
""" # 验证成功,返回user对象,否则返回None, 这个过程会将pwd进行hash后比较
user = auth.authenticate(username=username, password=pwd)
print(username)
print(pwd)
print(user)
# 如下直接调用 auth_user 表进行过滤,返回None,因为auth_user中对应的
# passward字段是存的hash后的密文。
# User.objects.filter(username=username,passward=pwd)
if user:
# @@@@@@@@@@@@@@@@@@@@@@@@
auth.login(request, user)
# 上面一行代码一执行,会生成 当前登录对象
# request.user = user 并注册对应的 session 记录
# 下次访问的时候直接用request.user就可以得到用户对象
# 未登录状态,request.user为匿名用户 AnonymousUser
# 基于用户认证装饰器,由于路径是写在请求头中的
# 所以要通过从GET中获取!
# (注意,这里并不与POST方法冲突,这里的GET只是请求中对应的字典)
# 如果没有取到next,默认/index/
next_url = request.GET.get("next", "/index/")
return redirect(next_url)
return render(request, "login.html")
# 基于用户认证组件的认证装饰器
@login_required
def index(request):
print("request.user:", request.user)
"""
未登录状态访问index,打印匿名用户 request.user: AnonymousUser
匿名用户:
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
request.user为全局变量,可以不用通过render
传递给模板直接在模板中使用就可以
"""
# 如果是匿名用户则为空
print("request.user.id:", request.user.id)
# 判断当前是否为匿名用户
print("匿名用户?", request.user.is_anonymous)
# if request.user.is_anonymous:
# if not request.user.is_authenticated:
# return redirect("/login/")
"""user对象的 is_authenticated()
如果是真正的 User 对象,返回值恒为 True 。 用于检查用户
是否已经通过了认证。通过认证并不意味着用户拥有任何权限,甚至
也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。
这个方法很重要, 在后台用request.user.is_authenticated()
判断用户是否已经登录,如果true则可以向前台展示request.user.name
"""
return render(request, "index.html")
# 注销
def logout(request):
"""
auth.logout(request)注销功能
"""
auth.logout(request)
return redirect("/login/")
# 基于用户认证组件的注册用户功能
# from django.contrib.auth.models import User 这个User就是表类对象
# 对应 django迁移自动生成的 auth_user 表
def reg(request):
if request.method == "POST":
username = request.POST.get("user")
pwd = request.POST.get("pwd")
# 千万不要这样操作,原因是这样不会hash密码!
# User.objects.create(username=username, password=pwd)
# 应该如下操作
user = User.objects.create_user(username=username, password=pwd)
return redirect("/login/")
else:
return render(request,"reg.html")
# 第一次访问order,没登录,跳转到login,
# 此时路径变为 http://127.0.0.1:8000/login/?next=/order/
# 当登陆后要求跳转到order, 在当前逻辑下,可在login视图函数中中获取next键值对,进行跳转。
@login_required
def order(request):
return HttpResponse("Hi, %s ,order welcome you!" % request.user.username)
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row text-center"><h2 style="color: rgba(15,159,99,0.94)">登录</h2></div>
<div class="row" style="padding: 0 18%;margin-top:50px;">
<form action="" method="post">
{% csrf_token %}
<div class="form-group">
<label for="user">用户名</label>
<input type="text" class="form-control" id="user" placeholder="用户名" name="user">
</div>
<div class="form-group">
<label for="Password">密码</label>
<input type="password" class="form-control" id="Password" placeholder="密码" name="pwd">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
</div>
</body>
</html>
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row">
<a href="/logout/" class="pull-right">注销</a>
<div class="row text-center">
{# request.user为全局变量,可以直接使用#}
<h2 style="color: rgba(15,159,99,0.94)">Hi, {{ request.user.username }}</h2>
</div>
</body>
</html>
templates/reg.html
与login.html代码一样!