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
		
		白名单  不设置任何权限校验的
'''
原文地址:https://www.cnblogs.com/-406454833/p/12012063.html