赞
踩
在我们构建一个网站的时候,想要对网站的资源进行访问控制,那么添加身份认证机制就是一个非常必要的办法
只有当访问者进行用户登录认证之后,才能对其开放网页的访问权限,甚至可以对用户进行分级管理,按照用户级别赋予用户不同的权限
最简单的认证机制只需要校验用户的登录名和密码,验证其是否与数据库中存储的用户数据一致,如果一致,则认证通过
以下是具体操作过程
我们的用户数据是要存储在数据库中的,那么必须要构造一个用户模型来存储用户的数据
最简单的模型,只有用户名和密码
# models.py
from django.db import models
class User(models.Model):
username = models.CharField(verbose_name='用户名', max_length=40, unique=True)
password = models.CharField(verbose_name='口令', max_length=256)
def __str__(self):
return self.username
在命令行中执行以下命令,使构建的用户模型生效
python manage.py makemigrations # 更新模型
python manage.py migrate # 在数据库中创建表结构
首先设计网页模板,这是用户与服务器进行交互的接口,也是服务器数据在用户端的展示窗口
<!-- login.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>登录</title> </head> <body> <div class="login"> <h2>欢迎登录!</h2> <br/> <form action="/login/" method="post"> {% csrf_token %} <p>账号: <input type="text" name="username" value=""> </p> <p>密码: <input type="password" name="password"> </p> <br/> <input type="submit" value="登录"> <button type="button" onclick="window.location.href='/register/'">注册</button> </form> <div>{{ mess }}</div> </div> </body> </html>
使用命令 startproject 创建的 Django 项目默认使用 CSRF 防护中间件 django.middleware.csrf.CsrfViewMiddleware,所以在每个表单中都需要加上 {% csrf_token %} 标签,否则 CSRF 校验不通过,触发 403 错误
可以在 setting 文件中修改列表 MIDDLEWARE 的值来关闭这个中间件,但不建议
<!-- register.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>用户注册</title> </head> <body> <div> <h2>请输入待注册的用户信息</h2> <form action="/register/" method="post"> {% csrf_token %} <p>账号: <input type="text" name="username"> </p> <p>密码: <input type="password" name="password"> </p> <p>再次输入: <input type="password" name="re_password"> </p> <br/> <input type="submit" value="注册用户"> </form> </div> <a href="/login/">返回登录</a> <div>{{ mess }}</div> </body> </html>
这里就比登录的多了个口令确认输入,相当地简单
视图函数是对用户请求的处理,这里定义对认证机制的一系列请求的处理函数
# views.py from django.shortcuts import render, redirect from Blog.models import User, Article def login(request): if request.session.get('is_login', None): # 检查是否已登录 return redirect('/index/') if request.method == 'POST': # 如果有提交表单 username = request.POST.get('username', '').strip() password = request.POST.get('password', '').strip() try: user = User.objects.get(username=username) except User.DoesNotExist: return render(request, 'login.html', {'mess': '用户不存在'}) else: if password == user.password: request.session['is_login'] = 'T' # 标记已登录 request.session['user_id'] = user.id request.session['username'] = username return redirect('/index/') else: return render(request, 'login.html', {'mess': '密码输入错误'}) return render(request, 'login.html') def logout(request): if request.session.get('is_login', None): request.session.flush() return redirect('/login/')
最简单的,只需要验证用户名和密码
验证通过,则在 session 中标记已登录和记录当前登录用户的一些信息,然后重定向到网站首页
验证不通过,返回错误提示信息
注销处理,只需要把 session 清空,然后重定向到登录页面
# views.py from django.shortcuts import render from Blog.models import User def register(request): if request.session.get('is_login', None): request.session.flush() if request.method == 'POST': username = request.POST.get('username', '').strip() password = request.POST.get('password', '').strip() re_password = request.POST.get('re_password', '').strip() if password == re_password: try: User.objects.get(username=username) except User.DoesNotExist: new_user = User(username=username, password=password) new_user.save() return render(request, 'register.html', {'mess': '用户注册成功'}) else: return render(request, 'register.html', {'mess': '该用户已被注册'}) else: return render(request, 'register.html', {'mess': '两次密码输入不一致'}) return render(request, 'register.html')
这里先验证了用户密码的两次输入是否一致,避免用户输入错误
如果不一致,直接返回错误提示信息
如果一致,则在数据库中查找用户名,看是否已被注册。如果未被注册,则注册成功,把新用户的数据存入数据库。否则,注册失败,返回错误提示信息
对于一些资源请求,我们设置需要登录认证过后才能进行访问
如果在每个请求的处理函数前面都添加一个登录检测,那么工程量比较大(如果很多请求),而且很丑相当不美观
这里我们可以使用 Python 的装饰器,在不需要改动原函数的情况下,扩展函数的功能
# views.py from django.shortcuts import render, redirect from Blog.models import Article from functools import wraps def check_login(func): @wraps(func) def inner(request, *arg, **kwargs): if request.session.get('is_login', None): return func(request, *arg, **kwargs) return redirect('/login/') return inner @check_login def index(request): arts = Article.objects.defer('body').order_by('modifield_time').reverse() return render(request, 'index.html', {'username': request.session.get('username'), 'arts': arts})
wraps 是一个可以确保调用装饰器时不会改变原函数属性(如模块名__name__)的东西
也可以使用 Django 内置的登录检测装饰器
# views.py
from django.shortcuts import render
from Blog.models import Article
from django.contrib.auth.decorators import login_required
@login_required
def index(request):
arts = Article.objects.defer('body').order_by('modifield_time').reverse()
return render(request, 'index.html', {'username': request.session.get('username'), 'arts': arts})
这个需要在 settings 文件中设置 LOGIN_URL 的值来指定跳转路径
最后把 url 请求和对应的视图函数进行关联
# urls.py
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('logout/', views.logout),
path('register/', views.register),
path('index/', views.index),
]
登录成果后,进入首页
从安全的角度上来看,上面实现的那个东西就跟被拔光了毛的老母鸡一样,任人宰割
所以我们需要给它多加点东西,加的东西放在后面几篇
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。