zoukankan      html  css  js  c++  java
  • Day 54 Django_模型层_用户认证&中间件

    用户认证

    创建一个用户

    python manage.py createsuperuser

    auth模块

    from django.contrib import auth

    django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:

    1、authenticate()

    提供了用户认证,即验证用户名以及密码是否正确,一般需要username password两个关键字参数
    如果认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!!

    user = authenticate(username='someone',password='somepassword')

    2 、login(HttpRequest, user)

    该函数接受一个HttpRequest对象,以及一个认证了的User对象
    此函数使用django的session框架给某个已认证的用户附加上session id等信息。

    from django.contrib.auth import authenticate, login
    
    def my_view(request):
      username = request.POST['username']
      password = request.POST['password']
      user = authenticate(username=username, password=password)
      if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
      else:
        # Return an 'invalid login' error message.
        ...

    3 、logout(request) 注销用户

    from django.contrib.auth import logout
    
    def logout_view(request):
      logout(request)
      # Redirect to a success page.

    该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

    代码示例:

    from django.shortcuts import render, HttpResponse, redirect
    from django.contrib import auth
    
    
    def auth_login(request):
        if request.method == 'POST':
            name = request.POST.get('user')
            pawd = request.POST.get('pawd')
    
            # 验证成功返回 username 对象,否则返回空
            user = auth.authenticate(username=name, password=pawd)
    
            if user:
                auth.login(request, user)  # 当前登录对象
                return redirect('/auth_info/')
        return render(request, 'login.html')
    
    
    def auth_info(request):
        print("request_user:",request.user.username)
        print("request_user_id:",request.user.id)
        print("request_user:",request.user.is_anonymous)    # 是否是匿名
    
        # 判断是否登录,如果是匿名,则跳转到登录界面
        if request.user.is_anonymous:
           return render(request,'login.html')
    
        username = request.user.username
        return render(request,'auth_info.html',locals())
    
    # 注销
    def auth_logout(request):
        auth.logout(request)
        return redirect('/auth_login/')

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>cookie</title>
    </head>
    <body>
    <form action="" method="post">
        {% csrf_token %}
        <label for="user">账号</label>
        <input type="text" id="user" name="user">
        <label for="pawd">密码</label>
        <input type="text" id="pawd" name="pawd">
        <input type="submit" value="登录">
    
    </form>
    </body>
    </html>

    auth_info.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>auth_info</title>
    </head>
    <body>
    {% csrf_token %}
    <h3>登陆成功:{{ username }}</h3>
    <a href="/auth_logout/">注销</a>
    </body>
    </html>

    User对象

    User 对象属性:username, password(必填项)password用哈希算法保存到数据库

    1 、user对象的 is_authenticated()

    如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
    通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name
    要求:
    1 用户登陆后才能访问某些页面,
    2 如果用户没有登录就访问该页面的话直接跳到登录页面
    3 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址

    方法1:

    def my_view(request):
      if not request.user.is_authenticated():
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

    方法2:
    django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()

    from django.contrib.auth.decorators import login_required
    
    @login_required
    def my_view(request):
      ...

    若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递 当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。

    2 、创建用户

    使用 create_user 辅助函数创建用户:

    from django.contrib.auth.models import User
    user = User.objects.create_user(username='',password='',email=''

    3 、check_password(passwd)

    用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True。

    4 、修改密码

    使用 set_password() 来修改密码

    user = User.objects.get(username='')
    user.set_password(password='')
    user.save

    认证装饰器

    setting.py

    LOGIN_URL="login"    # 根据自己需求

    装饰

    from django.contrib.auth.decorators import login_required
    
    
    @login_required()
    def index(request):
        '''
        装饰器装饰 index 
        :param request: 
        :return: 
        '''
        return render(request,'index.html')

    注册与修改代码示例

    注册

    from django.contrib.auth.models import User
    
    
    def auth_reg(request):
        '''
        注册
        :param request:
        :return:
        '''
        if request.method == 'POST':
            user = request.POST.get('user')
            pawd = request.POST.get('pawd')
            is_user = User.objects.filter(username=user)
            if not is_user:
                User.objects.create_user(username=user, password=pawd)
                return redirect('/auth_login/')
            return HttpResponse('用户已存在')
        return render(request, 'reg.html')

    修改密码

    auth_set.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>auth_set</title>
    </head>
    <body>
    <h3>修改密码</h3>
    <form action="" method="post">
        {% csrf_token %}
        <label for="user">账号</label>
        <input type="text" id="user" name="user" disabled="disabled" value={{ one_user }}>
        <label for="pawd">密码</label>
        <input type="text" id="pawd" name="pawd">
        <label for="pawd_two">确认密码</label>
        <input type="text" id="pawd_two" name="pawd_two">
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>

    views.py

    from django.contrib.auth.models import User
    def auth_set(request):
        '''
        修改密码
        :param request:
        :return:
        '''
        if request.method == 'POST':
            user = request.POST.get('user')
            new_pawd = request.POST.get('pawd')
            new_pawd_two = request.POST.get('pawd_two')
            if new_pawd == new_pawd_two:
                u = User.objects.get(username=user)
                u.set_password(new_pawd)
                u.save()
                return redirect('/auth_login/')
            return HttpResponse('两次密码输出的不一致')
    
        one_user = request.user
        return render(request,'auth_set.html',locals())

    中间件

    中间件的概念

    中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎使用,用不好会影响到性能。
    Django的中间件的定义:

    Middleware is a framework of hooks into Django’s request/response processing. <br>It’s a light, low-level “plugin” system for globally altering Django’s input or output.

    如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
    可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。
    Django默认的Middleware:

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    每一个中间件都有具体的功能。

    自定义中间件

    中间件中一共有四个方法:

    process_request
    process_view
    process_exception
    process_response

    1、process_request,process_response

    当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。

    上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin
    需要导入

    from django.utils.deprecation import MiddlewareMixin

     

    in views:

    def index(request):
    
        print("view函数...")
        return HttpResponse("OK")

    in Mymiddlewares.py:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
    
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            #return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response

    结果:

    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回

    注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:

    返回Md2中断的页面,后台打印如下:

    Md1请求  
    Md2请求  
    Md2返回  
    Md1返回

    流程图如下:

    2、process_view

    process_view(self, request, callback, callback_args, callback_kwargs)

    Mymiddlewares.py修改如下

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    class Md1(MiddlewareMixin):
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("Md1view")
    class Md2(MiddlewareMixin):
        def process_request(self,request):
            print("Md2请求")
            return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("Md2view")

    结果如下:

    Md1请求
    Md2请求
    Md1view
    Md2view
    view函数...
    Md2返回
    Md1返回

    下图进行分析上面的过程:

    当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户。

    process_view可以用来调用视图函数:

    class Md1(MiddlewareMixin):
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            # return HttpResponse("hello")
            response=callback(request,*callback_args,**callback_kwargs)
            return response

    结果如下:

    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回

    注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。

    3、process_exception

    process_exception(self, request, exception)

    示例修改如下:

    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            # return HttpResponse("hello")
            # response=callback(request,*callback_args,**callback_kwargs)
            # return response
            print("md1 process_view...")
        def process_exception(self):
            print("md1 process_exception...")
    class Md2(MiddlewareMixin):
        def process_request(self,request):
            print("Md2请求")
            # return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("md2 process_view...")
        def process_exception(self):
            print("md1 process_exception...")

    结果如下:

    Md1请求
    Md2请求
    md1 process_view...
    md2 process_view...
    view函数...
    
    Md2返回
    Md1返回

    流程图如下:

    当views出现错误时:

    将md2的process_exception修改如下:

    def process_exception(self,request,exception):
    
          print("md2 process_exception...")
          return HttpResponse("error")

    结果如下:

    Md1请求
    Md2请求
    md1 process_view...
    md2 process_view...
    view函数...
    md2 process_exception...
    Md2返回
    Md1返回

    应用案例

    1、做IP访问频率限制

    某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。

    2、URL访问过滤

    如果用户访问的是 login 视图(放过)
    如果访问其他视图,需要检测是不是有 session 认证,已经有了放行,没有返回 login,这样就省得在多个视图函数上写装饰器了!

    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',


    作为延伸扩展内容,有余力的同学可以尝试着读一下以下两个自带的中间件:

  • 相关阅读:
    Windows Server 2003 SP2(32位) 中文版 下载地址 光盘整合方法
    用Recycle()方法对Java对象的重要性
    Lotus中千奇百怪的 $$
    Developing a simple application using steps "User Decision" and "Mail"(1) 沧海
    沟通中的情绪管理(演讲稿) 沧海
    人只有在压力之下,才可能成功,没做一件事,都必须成功,不许言败 沧海
    什么是IDOC,以及IDOC的步骤 沧海
    VS2008 Professional Edition CHS中的deffactory.dat读取错误 沧海
    Including custom text in the step "User Decision" 沧海
    SAP Upgrade Strategy 沧海
  • 原文地址:https://www.cnblogs.com/ysging/p/12806188.html
Copyright © 2011-2022 走看看