• cookie操作, session操作, django中间件


    cookie, session, 及token的工作原理

    cookie与session

    为什么要有这些技术?

    • HTTP协议是无状态的, cookie和session是为了保持客户端的用户状态

    cookie:

    • 保存在客户端浏览器上的键值对,
    • cookie虽然是保存在客户端浏览器上的键值对, 但它是由服务端设置的
    • 浏览器有权禁止cookie的写入

    session:

    • 保存在服务端上面的键值对, session的工作机制是需要依赖于cookie的

    token

    1. 加密算法, salt: xxx
    2. 用户信息 + xxx --> 随机字符串
    3. 用户信息 + 随机字符串 --> res, 浏览器的cookie保存res
    4. 之后浏览器发送cookie, 服务端将res拆分成: 用户信息 + 随机字符串
    5. 服务端将用户信息通过相同的加密算法得出一个结果与拆分出的随机字符串进行比对

    优点: 一定程度保证了用户信息安全, 同时服务端不需要使用session存储用户信息

    cookie基本操作

    orm操作cookie

    • 通过HttpResponse对象给浏览器设置cookie: obj.set_cookie('k', 'v')
    • 通过request.COOKIES.get('k')获取浏览器携带的cookie值
    • 设置cookie的超时时间, max_age, expires(针对于IE浏览器)
    '''
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'jason' and password == '123':
                obj = redirect('/home/')
                obj.set_cookie('user', 'jason', expires=10)  # expires参数的值以秒为单位
                return obj
    
        return render(request, 'login.html')
    
    
    def home(request):
        if request.COOKIES.get('user'):
            return HttpResponse('登录成功')
            
        return redirect('/login/')
    '''
    

    基于cookie实现登录认证

    '''
    from django.shortcuts import render, HttpResponse, redirect
    from functools import wraps
    
    
    def login_auth(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            # 访问 http://127.0.0.1:8000/reg/?username=jason
            # print(request.path_info)  # /reg/, 只获取GET请求中的url
            # print(request.get_full_path())  # /reg/?username=jason, 获取GET请求中的url + url后面携带的参数
    
            # 校验用户是否登录
            if request.COOKIES.get('user'):
                res = func(request, *args, **kwargs)
                return res
            else:  # 用户未登录跳转到login页面, 同时在跳转到login的GET请求中携带原来想要访问的url
                target_path = request.path_info
                return redirect('/login/?next=%s' % (target_path,))
    
        return inner
    
    
    def login(request):
        ...
    
                old_path = request.GET.get('next')  # GET请求url后的携带参数一字典形式存放到request.GET中
                if old_path:  # 用户未登状态下录访问了本服务器的非login页面
                    obj = redirect(old_path)
                else:  # 用户直接访问本服务器的login页面
                    obj = HttpResponse('登录成功!')
    
                obj.set_cookie('user', 'jason')
    
                return obj
    
        return render(request, 'login.html')
    
    
    @login_auth
    def index(request):
        return HttpResponse('登录成功! 开始访问index页面')
    
    
    @login_auth
    def shopping(request):
        return HttpResponse('登录成功! 开始访问shopping页面')
    
    
    @login_auth
    def logout(request):
        obj = HttpResponse('注销成功, 已删除cookie!')  # 删除cookie
        obj.delete_cookie('user')
        return obj
    
    '''
    

    session基本操作

    • 设置session: request.session['k'] = 'v'

      1. django内部自动调用算法随机生成两个加密字符串, 一个对应"k", 一个对应"v"
      2. 在django_session表中的session_key字段插入"k"对应的加密字符串, session_data字段插入"v"对应的加密字符串
      3. 将"k"对应的加密字符串返回给前端, 浏览器中的cookie以 sessionid为key保存该字符串
    • django_session表中的expire_date默认为2周

    • 获取session: request.session.get('k')

      1. django内部会自动取请求头里获取cookie
      2. 拿着cooke中的sessionid所对应的加密字符串到django_session表中一一比对
      3. 如果比对上了, 会将: "k"对应的加密字符串, 以及{'k': 'v'}放到request.session对象中
    • django的session在创建数据的时候是针对浏览器的, 同一个浏览器只会在django_session表中生成一条数据

    • 删除session只删除对应浏览器的session

    • 能够作为数据库的有哪些

      ​ 数据库软件

      ​ 关系型
      ​ 非关系型
      ​ 文件
      ​ 内存

    def set_session(request):
        request.session['k'] = 'v'
        request.session['l'] = 'w'
        request.session.set_expiry(60)
        return HttpResponse('session设值成功!')
        # 报错: no such table: django_session, 解决: 执行数据库迁移命令, 会自动创建django_session表
    
    
    def get_session(request):
        res = request.session.get('k')
        
        if res:
            print(request.session)  # <... object at 0x000001A7B1402940>
            
            print(request.session.__dict__)
            # {'...session_key': 'vp3...', '_session_cache': {'k': 'v', 'l': 'w', '_session_expiry': 60}}
            
            return HttpResponse('获取session值: %s' % (res,))  # 获取session值: v
        
        else:
            return HttpResponse('session失效了!')
    
    
    def delete_session(request):
        # request.session.delete()  # 删除服务端session, 不删除客户端session
        request.session.flush()  # 同时删除客户端和服务端的session
        return HttpResponse('成功删除session值!')
    

    django中间件

    django默认的七个中间件都有各自独立的功能

    Scroll from Source按钮, 定位到当前文件具体所在的文件信息

    django支持自定义中间件, 有五个用户可以自定义的方法, 这五个方法会在特定阶段自动触发

    需要掌握的方法

    • process_request:
      • GET请求来时按照settings配置文件中从上往下依次执行每一个中间件内部定义的process_request方法
      • 如果中间件内部没有改方法, 会直接跳过
      • 该方法如果返回了HttpResponse对象, 那么GET请求会立即停止, 然后原路返回
      • 如果要做网站的全局性功能, 可以使用django中间件, 对象 + 字符串 --> 反射
        • 全局性的用户登录校验
        • 全局的用户访问频率校验(反爬措施)
        • 全局的用户权限校验
    • process_response
      • 响应走的时候按照settings配置文件中从下往上依次执行每一个中间件内部定义的process_response方法
      • 该方法有两个形参, 并且必须返回response形参, 否则会报错
      • 如果process_request方法返回了HttpResponse对象, 会直接从当前中间件中的process_response方法往回走, 没有执行的中间件不再执行
      • 该方法返回怎样的HttpResponse对象, 前端就会获得对应的数据
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    
    class MyMdd1(MiddlewareMixin):
        def process_request(self, request):
            print('第一个中间件中的process_request方法')
            # return HttpResponse('第一个中间件中的process_request方法的返回值')
    
        def process_response(self, request, response):
            """
            :param request:
            :param response: 后端返回给前端的数据
            :return:
            """
            print('第一个中间件中的process_response方法')
            return response
            # return HttpResponse('第一个中间件中的process_response方法返回的HttpResponse对象')
    
        def process_view(self, request, view_func, *view_args, **view_kwargs):
            print(view_func)  # <function mdzz at 0x00000243C024CA60>
            print(view_args)  # ((), {})
            print(view_kwargs)  # {}
            print('第一个中间件中的process_view方法')
    
        def process_exception(self, request, exception):
            print('第一个中间件中的process_exception方法')
            print(exception)  # name 'username' is not defined
    

    了解的方法, 能简单口述即可

    • process_view
      • 路由匹配成功之后, 视图函数执行之前触发该方法
    • process_templates_response
      • 如果形参中有response, 则必须要将其返回
      • 当返回的对象含有render属性, 且该属性指向一个render方法时触发
    • process_exception
      • 当视图函数中出现错误会自动触发, 顺序是从上往下

    课外拓展题: RBAC

    Role-Based Access Control: 基于角色的访问权限控制

    1. 用户登录是查询出其可以访问的url信息,
    2. 使用session存储url权限信息,
    3. 并将其返回给前端cookie
    4. 用户再次请求时, 使用request.path_info获取其访问的url与session中的url权限信息进行比对, 实现用户权限管理
    '''
    class User:
    		username
    		password
    		
    		1           jason	
    		2           egon
    		3           owen
    		
    	
    	class Permission:
    		title  # 权限名
    		url  # 权限对应的url
    		
    		添加用户				/add_user/
    		查看用户				/check_user/
    		编辑用户				/edit_user/d+/
    		删除用户				/delete_user/d+/
    		
    	
    	class User2Permission:
    		user
    		permission
    		
    		id             user_id         permission_id
    		1				1				1
    		2				1				2
    		3				1				3
    		4				1				4
    		
    		
    	CRM项目   6  8   客户关系管理系统
    	
    	
    		如何优化上面的权限管理     》》》     RBAC
    		
    		白名单  不设置任何权限校验的
    '''
    
  • 相关阅读:
    几种加密算法的java实现包括MD5、RSA、SHA256
    js 向form表单中插入数据
    HTTP的长短连接、长短轮询的区别(转载)
    try catch finally 关闭流标准的写法
    从黑格尔的正反合理论看人生的三个阶段
    《人人都是产品经理》读书笔记
    什么是PRD、MRD与BRD
    关于B/S系统中文件上传的大小限制怎么做
    如何向外行解释产品经理频繁更改需求为什么会令程序员烦恼?
    web页面开发笔记(不断更新)
  • 原文地址:https://www.cnblogs.com/-406454833/p/12012063.html
Copyright © 2020-2023  润新知