Django中间件进行用户登陆验证
Posted wateligx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django中间件进行用户登陆验证相关的知识,希望对你有一定的参考价值。
通常情况下我们在django中设置登陆验证,使用装饰器来检验是否登陆过。这种情况,我们所有的视图函数都需要加上,太low。
下面我们使用中间件来进行登陆验证~~~
我们先做出登陆页面:
1、models.py
#先在models中设置用户名密码字段 from django.db import models class UserInfo(models.Model): # nid = models.AutoField(primary_key=True) # nid = models.BigAutoField(primary_key=True) username = models.CharField(max_length=32) password = models.CharField(max_length=64)
2、新建forms.py
from django.forms import Form from django.forms import fields from django.forms import widgets
from django.core.exceptions import ValidationError class LoginForm(Form): username = fields.CharField( label=\'用户名\',#模板中使用form.username.label required=True, error_messages={ \'required\':\'用户名不能为空\' }, widget=widgets.TextInput(attrs={\'class\':\'form-control\'}) ) password = fields.CharField( label=\'密码\', required=True, error_messages={ \'required\': \'密码不能为空\' }, widget=widgets.PasswordInput(attrs={\'class\':\'form-control\'}) )
#form钩子
def clean_username(self):
if not self.cleaned_data.get("username").isdigit():
return self.cleaned_data.get("username")
else:
raise ValidationError("用户名不能全是数字")
3、views.py
# ############## 自定义配置 #################
USER_SESSION_KEY = "user_info"
from django.conf import settings# 仅用户自定义+内置
# from s18day24 import settings # 仅用户自定义
def login(request): #第一次请求走GET,显示初始登陆页 if request.method == "GET": form = LoginForm() return render(request,\'login.html\',{\'form\':form}) #如果是post请求,说明用户在登陆 else: #这里我们将request.POST字典完整的抛给form进行form校验 form = LoginForm(request.POST) #如果form校验成功 if form.is_valid(): # form.cleaned_data # {\'username\':\'alex\',\'password\':\'xxxx\'} # 数据库中查出是否存在用户名密码对应记录models.UserInfo.objects.filter(username=form.cleaned_data[\'user\'],password=form.cleaned_data[\'pwd\']) # models.UserInfo.objects.filter(**{\'username\':\'alex\',\'password\':123}) form.cleaned_data[\'password\'] = md5(form.cleaned_data[\'password\']) user = models.UserInfo.objects.filter(**form.cleaned_data).first() if user: # 将用户信息放置到session中,user.pk是UserInfo表的主键 request.session[settings.USER_SESSION_KEY] = {\'id\':user.pk,\'username\':user.username } return redirect(\'/index/\') else:
#给errors_message字典添加错误信息 form.add_error(\'password\', \'用户名或密码错误\') return render(request, \'login.html\',{\'form\':form})
@auth#添加装饰器后使用
def index(request):
return HttpResponse(\'欢迎登陆\')
4、login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> #novalidate不适用浏览器自带验证功能 <form method="post" novalidate> {% csrf_token %} #form提供的label属性errors错误字典,form生成html <p>{{ form.username.label }}: {{ form.username }} {{ form.username.errors.0 }}</p> <p>{{ form.password.label }}: {{ form.password }} {{ form.password.errors.0 }}</p> <input type="submit" value="提交"> </form> </body> </html>
md5加密模块
import hashlib def md5(text): m = hashlib.md5() m.update(text.encode(\'utf-8\')) return m.hexdigest()
5、urls.py模块
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ # url(r\'^admin/\', admin.site.urls), url(r\'^login/\', views.login), url(r\'^index/\', views.index), url(r\'^test/\', views.test), ]
这种情况下,我们是可以轻松直接访问index页面的
我们想让用户在未登录的情况下不允许访问index,需要添加个装饰器来进行校验是否登陆,方法如下。
def auth(func): def inner(request,*args,**kwargs): # 在登陆时,我们给登陆成功的用户设置了session,在执行视图函数之前,我们获取用户访问session看能否找到 user_info = request.session.get(settings.USER_SESSION_KEY) if not user_info: return redirect(\'/login/\') # 执行视图函数 response = func(request,*args,**kwargs) return response return inner
dango的生命周期
我们抛开装饰器用户,我们先来说下django一条请求的生命周期
一条请求进入dango我们通常用到的,请求进入我们设置id路由系统,进行url匹配视图函数,在视图函数中进行一些验证、数据库操作、渲染html等操作。
在我们进入url试图函数之前,请求实际还会经过几个中间件,其实就是几个定义的类,我们知道的 csrf校验就是从这里面进行的。
我们可以这样找到这些类
在setting中middleware中定义的就是一个个中间件
我们使用from。。。import的方法ctrl点击找到这个类
我们在项目中新建个middlwares文件
创建个py文件md.py,定义两个类,m1、m2
setting中配置上路径
在django1.7或1.8的时候
我们在自定义的中间件中那么定义
class M1(object): def process_request(self,request,*args,**kwargs): pass def process_response(self,request,response): return response
class M2(object):
def process_request(self,request,*args,**kwargs):
pass
def process_response(self,request,response):
return response
1.10之后,中间件默认会先执行__call__方法
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, \'process_request\'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, \'process_response\'): response = self.process_response(request, response) return response
执行顺序为 m1.process_request-->m2.process_request-->m2.process_response-->m1.process_response
注:其中retrun response 的作用是为了传递前面函数的返回内容
from django.conf import settings from django.shortcuts import redirect class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, \'process_request\'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, \'process_response\'): response = self.process_response(request, response) return response class M1(MiddlewareMixin): def process_request(self,request,*args,**kwargs): #如果是登陆页面,returnNone跳过 if request.path_info==\'/login/\': return None #如果是其他url,进行校验是否登陆 user_info=request.session.get(settings.USER_SESSION_KEY) if not user_info: return redirect(\'/login/\') def process_response(self,request,response): #用于传递给前面的类 print("m1.process_response") return response
如上,我们将session验证登陆放到中间件中,便可以替代装饰器了~
中间件中定义的方法是固定的,常用的是process_request和process_response,还有一些其他的方法:
process_view(self,request,callback,callback_args,callback_kwargs): 当执行完process_request之后,会重新回到入口执行process_view然后执行url函数。
process_exception(request,exception):如果项目中模块中出现异常,返回时会先执行中间件的process_exception,之后回到返回点执行process_response。
总结:
1、settings 中middleware中添加自定义中间件路径
\'middlwares.auth.M1\',
2、新建middlwares文件夹auth文件
3、1.10版本以上自定义中间件类需要继承MiddlewareMixin
4、须有 process_request ,和process_response方法,process_response的需要返回return response,process_request 默认return None相当于跳过该中间件。
以上是关于Django中间件进行用户登陆验证的主要内容,如果未能解决你的问题,请参考以下文章