• Django框架-cookie和session以及中间件


    一、cookie 和 session

    1.为什么会有这些技术

    cookie和session的出现是为了保存客户端的用户状态。

    究其本质,其实是因为HTTP协议是无状态的,没办法保存客户的登录信息及状态,因此需要用cookie和session来保存用户的状态。

    cookie

    cookie是客户端用来记录用户信息的一种容器,它以键值对的形式储存,比方说{'username':'st'}

    当cookie发送到服务端后,服务端可以根据cookie携带的信息识别用户的身份。可以知道到底是张三在访问服务器还是李四在访问服务器。

    这样就导致某些功能在被用户使用时,必须先登录,让服务端知道用户身份后才能使用。比如说淘宝的购物车,每个人都不一样,你只有登陆了,才能访问自己的购物车。

    这就导致用户每次访问都要登录,显得很麻烦。如果可以登陆一次就可以记录状态,那就很方便了。

    cookie应运而生。

    用户登录后,登录信息保存在浏览器cookie中,只需登录一次输入信息,下一次再访问,浏览器就会自动帮你发送cookie。

    服务端得知了用户信息,你也不用手动输入多次了,万事大吉,美滋滋!

    session

    万事无绝对。

    cookie记录的用户信息往往包含了一些隐私信息。比如密码之类的敏感信息。

    当cookie保存在浏览器时,cookie中的信息就会遭受各种意外泄露的风险。

    一旦泄露,有可能会酿成大祸。

    为了解决这个问题,session横空出世。

    当用户输入信息登录时,用户信息被传入后端服务器,服务器将这些数据进行加密并保存在服务器中,然后给这份信息贴上一个名为"session_id"的标签。这个"session_id"其实只是一个随机生成的字符串,用来标记这份用户信息,方便查找的。

    通过这个"session_id",服务器就可以快速的访问到这份用户信息。

    这样有什么用呢?

    这样浏览器就不用直接保存用户信息了。服务端可以将"session_id"返回给浏览器,浏览器将"session_id"当做cookie键值对中的值进行保存。

    这样,下次用户想要进行访问时,浏览器就将包含"session_id"的cookie发给服务器,服务器通过"session_id"找到之前用户第一次登陆时保存在服务器上的信息,服务器就可以知道用户身份惹!

    至此登陆成功!用户再也不用频繁输入信息,也不怕信息泄露惹!

    当然,session也并不完美,但是安全性能相比于只有cookie时已经大大提高,从而被广而告之,程序员们纷纷效仿。。。

    虽然cookie可以保存在客户端浏览器上,但是由于它是由服务端设置出来的,浏览器有权禁止cookie的写入。

    2.1 Django如何设置cookie

    需要用views三基类实例化出的obj对象进行cookie设置。

    obj = HttpResponse()
    # 利用obj对象你才可以操作cookie
    # obj = render()
    # obj = redirect()
    
    obj.set_cookie('k1','v1')
    # 设置用盐加密的cookie
    obj.set_signed_cookie(key,value,salt='加密盐',)
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'st' and password == '123':
                # 如果登录信息完整,就返回主页
                obj = redirect('/home/')
                
    		   # 告诉浏览器,保存这一对cookie
                obj.set_cookie('username','st')
                
                return obj
        return render(request,'login.html')
    

    2.2 Django如何获取cookie

    def home(request):
        if request.COOKIES.get('username'):
            print(request.COOKIES.get('username'))
            # st
            return HttpResponse('只有登录的人才能看到')
        return redirect('/login/')
    

    2.3 Django如何设置cookie的超时时间

    set_cookies使用max_age、expires参数

    obj.set_cookie('k1','v1',max_age=3)
    obj.set_cookie('k1','v1',expires=3)
    # 两个参数都是设置超时时间  并且都是以秒为单位
    # 区别:expires可以给IE浏览器设置cookie的超时时间
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'st' and password == '123':
                obj = redirect('/home/')
                obj.set_cookie('username','st',expires=3)
                # 告诉浏览器,保存这一对cookie
                # expires=3单位为秒,max_age一样
                return obj
        return render(request,'login.html')
    

    2.4 Django如何通过cookie跳转到想要访问的页面

    可以在登录认证装饰器中完成

    # 用来跳回用户登录前想访问的页面的装饰器
    from functools import wraps
    def login_auth(func):
        @wraps(func)  # 函数用wraps,类用update_wrapper
        def inner(*args,**kwargs):
            # 判断当前用户是否登录
            request = args[0]
            # print(request)
            # print(request.GET)
            # print(request.path_info)  # 只获取url,不获取get参数
            # print(request.get_full_path())  # # url+get参数
            if request.COOKIES.get('username'):
                res = func(*args, **kwargs)
                return res
            else:
                # 获取到用户想要访问的页面的url
                path = request.path_info
                # 将该url当做get参数传入login函数
                return redirect(f'/login/?path={path}')
        return inner
    
    
    # login
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'st' and password == '123':
                # 获取get参数,取得用户想要访问的url
                path = request.GET.get('path')
                if path:
                    obj = redirect(path)
                else:
                    # 如果path没值,可能用户是直接访问的login视图,因此登录后默认返回到home首页
                    obj = redirect('/home/')
    
                obj.set_cookie('username','st')
                return obj
        return render(request,'login.html')
    

    2.5 Django如何删除cookie

    delete_cookie函数删除cookie。

    def logout(request):
        obj = redirect('/logout/')
        obj.delete_cookie('username')
        return obj
    

    3. session

    session是保存在服务端上的键值对。

    session的工作机制是需要依赖于cookie的。

    3.1 Django设置session

    默认失效时间为两周,14天

    def set_session(request):
        request.session['k1'] = 'ok123'
        return HttpResponse('session已设置')
    

    Django内部到底发生了什么:

    1. 将获取到的数据以键值对的形式添加到一个大字典中,将这个字典加密保存。
    2. 自动生成一个随机的字符串,作为上一步获取的加密数据的session_id。以键值对{'session_id':加密数据}的形式保存在储存器中。可以通过session_id来获取对应的加密数据。
    3. 将session_id返回给前端浏览器。这样下次浏览器访问时携带cookie,服务器后端可以获取cookie中的session_id,这样就可以通过session_id获取储存器中储存的加密数据。然后通过‘加密数据加密时使用的加密算法’所对应的解密算法将加密数据解密,就可以获取以键值对形式储存的数据了。
    4. 当下一次同一个浏览器需要在储存一组隐私数据时,django自动解密出该浏览器所对应的大字典,将新加入的键值对添加到这个大字典中,重新加密,保存,替代之前的加密大字典,这样,一个浏览器就会只有一条数据了。

    3.2 Django获取session

    # 获取session
    def get_session(request):
        res = request.session.get('k1')
        print(res)
        return HttpResponse('获取成功')
    

    Django内部到底发生了什么:

    1. Django服务端从前端浏览器处获取到cookie
    2. 从cookie中取出相应的'session_id'值
    3. 在数据库中通过session_id获取对应的大字典加密值
    4. 将加密大字典解密,获取大字典
    5. request.session=大字典
    6. 然后request.session就可以通过'.get'的方式从字典中取值了。
    res = dict(request.session)
    print(res)
    
    # 强制类型转换一下,发现确实是一个字典
    # {'k1': 'ok123', 'k2': 'ok321'}
    

    3.3 Django删除session

    # 删除session
    def del_session(request):
        
        # 删除当前会话的所有Session数据
        # request.session.delete()
        
        # 删除当前的会话数据并删除会话的Cookie,
        # 用于确保前面的会话数据不可以再次被用户的浏览器访问.建议使用
        request.session.flush()
        return HttpResponse('shanle ')
    

    3.4 Django设置session失效时间

    # request.session.set_expiry(value)
    request.session.set_expiry(5)  # 单位为秒
    

    当某条session失效后,这个数据就会从有效的大字典中被筛选出,单独放在session表里作为一条数据,它不会立马被清除,而是先存在session表里,每过一段时间,django就会启用自动清除功能,将失效时间已过的session删除。

    3.5 Django设置储存session的存储器

    1. 数据库Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
    
    2. 缓存Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
    
    3. 文件Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 
    
    4. 缓存+数据库
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
    
    5. 加密Cookie Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
    
    其他公用设置项:
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
    
    Django中Session相关设置
    

    二、Django中间件

    1. 默认中间件

    如果你想要做一些网站的全局性功能,你都应该优先考虑使用django的中间件。

    例如:

    1.全局的用户登录校验
    2.全局的用户访问频率校验
    3.全局的用户权限校验()

    django的中间件是所有框架里面做的最完善的。

    # settings
    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',
    ]
    

    以上就是django默认的七种中间件。

    中间件的本质其实就是一个个的类,类中的以下方法会在特定的阶段自动触发:

    1.process_request

    2.process_response

    3.process_view

    4.process_template_response

    5.process_exception

    2. 自定义中间件

    自定义中间件需要自己创建一个py文件,名字可以随便取,然后在这个文件中导入MiddlewareMixin模块产生子类。

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse,render,redirect
    # 接下来可以定义类,继承MiddlewareMixin模块,该类就成为了一个中间件
    
    class MyMdd1(MiddlewareMixin):
        def process_request(self,request):
            pass
        
    # 。。。。。。
    

    2.1. 需要掌握

    1. process_request

      1.请求来的时候会按照settings配置文件中从上往下的顺序,依次执行每一个中间件内部定义的process_request方法。

      2.如果中间件内部没有该方法,直接跳过执行下一个中间件。

      3.该方法一旦返回了HttpResponse对象,那么请求会立刻停止往回走,立即原路返回。

      4.当process_request方法直接返回HttpResponse对象之后 会直接从当前中间件里面的process_respone往回走。原路返回。没有执行的中间件都不会再执行。

    def process_request(self,request):
        print('我是第一个中间件里面的process_request方法')
        # return HttpResponse("我是中间件一里面的")
    
    1. process_response

      1.响应走的时候会按照settings配置文件中从下往上的顺序,依次执行每一个中间件内部定义的process_response方法。

      2.该方法必须有两个形参,并且必须返回response形参,不返回直接报错。

      3.该方法返回什么(HttpResponsed对象)前端就能获得什么。

    def process_response(self,request,response):
    	"""
    	:param request:
    	:param response: 就是后端返回给前端的数据
    	:return:
    	"""
    	print('我是第一个中间件里面的process_response方法')
    	return response
    

    2.2 了解

    1. process_view

      1.路由匹配成功之后执行视图函数之前触发。

      2.如果该方法返回了HttpResponse对象,那么会从下往上一次经过每一个中间件里面的process_response方法。

    def process_view(self,request,view_name,*args,**kwargs):
        print(view_name)  # 函数内存地址
        print(args)
        print(kwargs)
        print('我是第一个中间件里面的process_view方法')
    
    1. process_template_response

      1.在视图函数执行完成后立即执行,但有一个前提条件,那就是视图函数返回的对象必须有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。不然不会触发。

    def process_template_response(self, request, response):
        print('我是第一个中间件里面的奇葩方法')
        return response
    
    
    # views
    def mdzz(request):
        print('我是视图函数mdzz')
        def render():
            return HttpResponse('你好呀 我是奇葩')
        obj = HttpResponse('我很好 好的像个傻逼一样')
        obj.render = render
        return obj
    
    1. process_exception

      1.当视图函数中出现错误时会自动触发,顺序是从下往上

    def process_exception(self,request,exception):
        print('我是第一个中间件里面的process_exception')
        print(exception)
    
  • 相关阅读:
    linux下的磁盘挂载
    shell中的循环语句while
    hadoop安装和配置
    shell 命令 创建/删除 软连接 ln -s
    azkaban disable 停用部分工作流
    git dev 分支merge到master
    shell 命令 zip unzip
    git代码同步服务器代码需要注意的问题
    shell 命令 if elif else fi 用法
    python 引入本地 module
  • 原文地址:https://www.cnblogs.com/bowendown/p/11986507.html
Copyright © 2020-2023  润新知