Django 实现网站登录认证机制

在我们构建一个网站的时候,想要对网站的资源进行访问控制,那么添加身份认证机制就是一个非常必要的办法
只有当访问者进行用户登录认证之后,才能对其开放网页的访问权限,甚至可以对用户进行分级管理,按照用户级别赋予用户不同的权限

简单的登录认证机制

最简单的认证机制只需要校验用户的登录名和密码,验证其是否与数据库中存储的用户数据一致,如果一致,则认证通过
以下是具体操作过程

构建用户模型

我们的用户数据是要存储在数据库中的,那么必须要构造一个用户模型来存储用户的数据

最简单的模型,只有用户名和密码

# 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 路由设置

最后把 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),
]

效果展

login
登录成果后,进入首页
index

安全机制

从安全的角度上来看,上面实现的那个东西就跟被拔光了毛的老母鸡一样,任人宰割
所以我们需要给它多加点东西,加的东西放在后面几篇

传送门:
口令存储
用户枚举
注册页面的用户枚举
口令爆破

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值