• 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相当于跳过该中间件。
    
    
  • 相关阅读:
    每日一水 POJ8道水题
    编译和使用 MySQL C++ Connector
    j2ee model1模型完成分页逻辑的实现 详解!
    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号
    指向结构体变量的指针
    EOSS V3.0 企业运营支撑系统(基于RBAC原理的权限管理)
    MybatisGen1.0 Mybatis JavaBean Mapper生成工具
    The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by
    资源-Android:Android
    软件-开发软件:Android Studio
  • 原文地址:https://www.cnblogs.com/kunixiwa/p/8157296.html
Copyright © 2020-2023  润新知