zoukankan      html  css  js  c++  java
  • Django中的Session和cookie

    Session和cookie

    • 参考文献:https://www.cnblogs.com/wupeiqi/articles/5246483.html

    1.问题引入

    1.1 cookie是什么?

    • 保存在客户端浏览器上的键值对

    1.2 Sessions

    • 保存在服务端的数据(本质上是键值对)

      • 应用:依赖Cookie

      • 作用:保持会话(web网站)

      • 好处:敏感信息不会直接给客户端

    • image-20220105095100288

    1.3 简单示例

    • image-20220105100844552
    • image-20220105102452687

    2.cookie

    • cookie进行维持会话,一个浏览器只能存储20个cookie,服务端上限为300cookie

      • 注意:cookie大小不能超过4kb
    • cookie一般不会设置中文

    # 中文cookie的设置一般有两种方式
    # 1、使用decode('iso-8859-1').encode('utf-8')的方式
    # 字符串不能直接使用decode因此,注意使用顺序
    # 2、使用json,进行序列化,返回的方式为unique编码的字符串
    

    2.1 简单应用

    • 登录界面设置cookie防止其他非登录界面的人员进行访问
    from django.shortcuts import render,redirect,HttpResponse
    
    # Create your views here.
    
    
    def index(request):
        if request.COOKIES.get('is_login')=='True':
            return render(request,'index.html')
        else:
            return HttpResponse('你没成功!')
    
    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        if request.method=='POST':
            username=request.POST.get('username')
            pwd=request.POST.get('pwd')
            if username=='aaa' and pwd=='666':
                ret=redirect('index')
                # 设置cookie的键值对
                ret.set_cookie('is_login',True)
                print('访问成功')
                return ret
            else:
                return redirect('login')
    
    • 注意:cookie虽然可以实现登录的验证,但是会将状态设置在客户端浏览器,因此并不安全。

    2.2 cookie的分发与验证

    • 使用装饰器进行封装cookie的分发与验证

    • 装饰器的简单复习
    #编写装饰器
    def wapper(f):
        #装饰器的参数f为引用@下面的相关函数
        def inner(request,*args,**kwargs):
            # 决定执行先后的分界线
            ret=f(*args,**kwargs)
            
            return ret
        return inner
    # 调用装饰器
    @wapper
    def test():
        pass
    
    '''
    知识点
    函数内部定义一个函数,该函数要调用一下原函数的参数
    最外层函数的返回值为内层函数
    装饰器的调用
    @name
    *************
    装饰器与Python 的闭包相关联,且知识点与js的函数参数可以为函数高度相似
    '''
    
    • 装饰器的cookie
    from django.shortcuts import render,redirect,HttpResponse
    
    # Create your views here.
    
    
    #编写装饰器
    def wapper(f):
        def inner(request,*args,**kwargs):
            is_loin=request.COOKIES.get('is_login')
            if is_loin=='True':
                ret=f(request,*args,**kwargs)
                return ret
            else:
                return redirect('login')
        return inner
    
    # 调用装饰器
    @wapper
    def index(request):
        return render(request,'index.html')
    
    # 登录函数设置cookie不变
    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        if request.method=='POST':
            username=request.POST.get('username')
            pwd=request.POST.get('pwd')
            if username=='aaa' and pwd=='666':
                ret=redirect('index')
                ret.set_cookie('is_login',True)
                # print('访问成功')
                return ret
            else:
                return redirect('login')
    
    <!--相关的两个html文件-->
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陆界面</title>
    </head>
    <body>
    
        <h1>前进,前进,不择手段的前进</h1>
        <hr>
        <form method="post" action="">
            {% csrf_token %}
            用户名:<input type="text" name="username">
            <br>
            密码:<input type="password" name="password">
            <button type="submit">提交</button>
        </form>
    </body>
    </html>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>自然选择,前进四</h1>
    </body>
    </html>
    

    2.3设置cookie的有效期

    ret.set_cookie('name', 'AA',10)
    ret.set_cookie('sex', 'male',10)
    

    image-20210326221531916

    2.5 cookie的其他设置

    rep = HttpResponse(...) 或 rep = render(request, ...)
     
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)
        参数:
            key,              键
            value='',         值
            max_age=None,     超时时间
            expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
            path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
            domain=None,      Cookie生效的域名
            secure=False,     https传输
            httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
    

    2.6 cookie的缺点

    • cookie键值对存在与本地的浏览器文件安全性较低

    例如

    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        if request.method=='POST':
            username=request.POST.get('username')
            pwd=request.POST.get('pwd')
            if username=='aaa' and pwd=='666':
                ret=redirect('index')
                ret.set_cookie('is_login',True)
                ret.set_cookie('name', 'AA')
                ret.set_cookie('sex', 'male')
                # print('访问成功')
                return ret
            else:
                return redirect('login')
    

    image-20210326215641189

    3.seesion会话

    • session的相关数据(键值对)默认存储在服务端的数据库中django_session表中。

    • 一个用户,一个浏览器只保存一条记录

    • seesion的默认过期时间是两周,可以手动设置

    • 生成cookie为加密后的字符串,数据存储在django_session数据表之中

      • 可以在setting-global里面修改seesion_id的名称,与数据库表中的键相对应。
      • image-20210326215652168

    3.1 一般使用

    def login(request):
        """ 用户名和密码登录 """
        if request.method == 'GET':
            form = LoginForm(request)
            return render(request, 'login.html', {'form': form})
        form = LoginForm(request,data=request.POST)
        if form.is_valid():
            # 用户输入正确,登陆成功
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            # 账号可能为邮箱或者是手机号
            '''
                查询逻辑:username=手机号或者是邮箱,但是验证码均等于验证码
                        (username=moblie_phone and password=password)or(username=email and password=password)
                属于复杂查询条件,因此使用orm的Q查询
            '''
            user_obj = models.UserInfo.objects.filter(Q(email=username) | Q(moble_phone=username)).filter(
                password=password).first()
            if user_obj:
                '''登录成功为1'''
                # session使用步骤
                # 1.生成随机字符串
                # 2.通过cookie发送到客户端
                # 3.保存到服务端值
                request.session['username'] = user_obj.username
                # 上句代码可完成上述的所有操作。
                request.session.set_expiry(60 * 60 * 24 * 14)  # 设置session的时间为两周
                return redirect('home')
            # 登录失败
            form.add_error('username', '用户名或密码错误')
        return render(request, 'login.html', {'form': form})
    

    3.2session和cookie的有效期

    • seesion的默认过期时间是两周,可以手动设置
    request.session.set_expiry(60 * 60 * 24 * 14)
    
    • 逻辑可参考上述(一般使用)代码

    image-20210326221800424

    from django.shortcuts import render,redirect,HttpResponse
    
    # Create your views here.
    
    def index(request):
    
        # is_login=request.session['is_login']
        '''
            1.从cookie里面拿出了session_id:xxx随机字符串拿出来
            2、去django-session表里面查询到相对应的数据
            3.反解密用户存储的数据,并获取用户的数据
        '''
        is_login = request.session.get('is_login')
        if is_login==True:
            return render(request,'index.html')
        else:
            return redirect('home')
    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        if request.method=='POST':
            username=request.POST.get('username')
            pwd=request.POST.get('password')
            if username=='aa' and pwd=='300':
                # 设置seession
                request.session['is_login']=True
                request.session['name']='AA'
                '''
                    1、生成ssesion_id:随机字符串
                    2、在COOKIE里面加上了键值对:session_id:ZDsrf
                    3.将用户的数据进行加密并保存到DJANGO-SESSION表里面,形式为一条记录
                    # 数据库中session_key  随机字符串
                    # seesion_data:用户加密的数据
                
                '''
                return redirect('index')#redict里面的字符串为URL的别名,进行反向解析
            else:
                return HttpResponse('请正常登录')
    

    3.3 seession的装饰器

    装饰器函数一般要写在被装饰函数的上方,以免语法错误

    def session_author(fn):
    
        def inner(request,*args,**kwargs):
            status=request.session.get('is_login')
            if status:
                ret=fn(request)
                return ret
            else:
                # return redirect('login'),#使用reverse进行反向解析
                return redirect(reverse('login'))
        return inner
    

    与cookie的装饰器相似。

    • 注:上述装饰器可用作判断用户是否登录,但是在django中使用较少。django中一般使用中间件判断用户是否登录。并设置对应的白名单。

    3.4 Session操作。

    • 可以进行增删改查。

    • 增加就是登录时的写入,修改可以直接像字典一样进行修改。

    • 删除seesion

      def logout(request):
          # 清楚Session
          request.session.flush()
          return redirect('home')
      

      常用作用户注销登录的实现。

    • 获取seesion

      中间件中获取判断

      class AuthMiddleware(MiddlewareMixin):
      
          def proccess_request(self,request):中
              '''如果用户已登录,则request中赋值'''
              user_name=request.session.get('user_name',0)
              # 在中间件中获取值,不存在,则默认值是0,获取到用户的user_name
              userobj=models.UserInfo.objects.filter(user_name=user_name)
              # 根据用户的username去数据库中进行查询,查询到结果userobj赋值给request
              # 中,如果request中的tracer有值,则认定为已经登录,反之则认为没登录。
              request.tracer=userobj
              # 如果tracer的值比较多,则可以定义一个类,专门进行保存
      
    • 完整登录中间件模板
      #!/usr/bin/env python
      # -*- coding:utf-8 -*-
      import datetime
      from django.shortcuts import redirect
      from django.utils.deprecation import MiddlewareMixin
      from django.conf import settings
      
      from web import models
      
      
      class Tracer(object):
      
          def __init__(self):
              self.user = None
              self.price_policy = None
              self.project = None
      
      
      class AuthMiddleware(MiddlewareMixin):
      
          def process_request(self, request):
              """ 如果用户已登录,则request中赋值 """
      
              request.tracer = Tracer()
      
              user_id = request.session.get('user_id', 0)
              user_object = models.UserInfo.objects.filter(id=user_id).first()
              request.tracer.user = user_object
      
              # 白名单:没有登录都可以访问的URL
              """
              1. 获取当用户访问的URL
              2. 检查URL是否在白名单中,如果再则可以继续向后访问,如果不在则进行判断是否已登录
              """
              if request.path_info in settings.WHITE_REGEX_URL_LIST:
                  return
              # 检查用户是否已登录,已登录继续往后走;未登录则返回登录页面。
              if not request.tracer.user:
                  return redirect('login')
      
              # 登录成功之后,访问后台管理时:获取当前用户所拥有的额度
      
              # 方式一:免费额度在交易记录中存储
      
              # 获取当前用户ID值最大(最近交易记录)
              _object = models.Transaction.objects.filter(user=user_object, status=2).order_by('-id').first()
              # 判断是否已过期
              current_datetime = datetime.datetime.now()
              if _object.end_datetime and _object.end_datetime < current_datetime:
                  _object = models.Transaction.objects.filter(user=user_object, status=2, price_policy__category=1).first()
      
              request.tracer.price_policy = _object.price_policy
      
              # 方式二:免费的额度存储配置文件
              """
              # 获取当前用户ID值最大(最近交易记录)
              _object = models.Transaction.objects.filter(user=user_object, status=2).order_by('-id').first()
      
              if not _object:
                  # 没有购买
                  request.price_policy = models.PricePolicy.objects.filter(category=1, title="个人免费版").first()
              else:
                  # 付费版
                  current_datetime = datetime.datetime.now()
                  if _object.end_datetime and _object.end_datetime < current_datetime:
                      request.price_policy = models.PricePolicy.objects.filter(category=1, title="个人免费版").first()
                  else:
                      request.price_policy = _object.price_policy
              """
      
          def process_view(self, request, view, args, kwargs):
      
              # 判断URL是否是以manage开头,如果是则判断项目ID是否是我创建 or 参与
              if not request.path_info.startswith('/manage/'):
                  return
      
              project_id = kwargs.get('project_id')
              # 是否是我创建的
              project_object = models.Project.objects.filter(creator=request.tracer.user, id=project_id).first()
              if project_object:
                  # 是我创建的项目的话,我就让他通过
                  request.tracer.project = project_object
                  return
      
              # 是否是我参与的项目
              project_user_object = models.ProjectUser.objects.filter(user=request.tracer.user, project_id=project_id).first()
              if project_user_object:
                  # 是我参与的项目
                  request.tracer.project = project_user_object.project
                  return
      
              return redirect('project_list')
      
      

    3.5 Session配置文件补充及存储

    1.数据库存储
    Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
     
    a. 配置 settings.py
     
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
         
    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,默认修改之后才保存(默认)
     
     
     
    b. 使用
     
        def index(request):
            # 获取、设置、删除Session中数据
            request.session['k1']
            request.session.get('k1',None)
            request.session['k1'] = 123
            request.session.setdefault('k1',123) # 存在则不设置
            del request.session['k1']
     
            # 所有 键、值、键值对
            request.session.keys()
            request.session.values()
            request.session.items()
            request.session.iterkeys()
            request.session.itervalues()
            request.session.iteritems()
     
     
            # 用户session的随机字符串
            request.session.session_key
     
            # 将所有Session失效日期小于当前日期的数据删除
            request.session.clear_expired()
     
            # 检查 用户session的随机字符串 在数据库中是否
            request.session.exists("session_key")
     
            # 删除当前用户的所有Session数据
            request.session.delete("session_key")
     		# "session_key"指的是 request.session.session_key
            request.session.set_expiry(value)
                * 如果value是个整数,session会在些秒数后失效。
                * 如果value是个datatime或timedelta,session就会在这个时间后失效。
                * 如果value是0,用户关闭浏览器session就会失效。
                * 如果value是None,session会依赖全局session失效策略。
    
    2.缓存Session
    • 缓存,存储在另一台(缓存服务器)机器内存中的数据。一般结合redis使用
    a. 配置 settings.py
     
        SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
        SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
     
     
        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,默认修改之后才保存
     
     
     
    b. 使用
     	同上
    
    3.其他

    文件Session

    缓存+数据库Session

    加密cookie Session

    以上方式请点击参考文献进行观看。

    4.装饰器的补充

    def warper(f):
        def inner(*args,**kwargs):
            print('我是执行前的语句')
            ret=f()
            print('我是执行后的语句')
            return ret# 返回原函数的返回结果
        return inner
    
    @warper#执行wapper函数把test1当做参数
    def tes1():
        print('***********')
        return '我是原函数的返回结果'
    print(tes1())
    

    image-20210330185836720

    5.知识梳理

    image-20220105103839285

    继续努力,终成大器!

  • 相关阅读:
    softice 在winice中的安装 zt
    普通版和优秀版简历的20项对比
    今天又投了几家。。等啊。。。
    乱写
    反攻击技术综合分析报告
    今天投简历的公司
    #pragma 预处理指令详解
    黑客入侵无线网络常用手段
    ADODB.Stream漏洞
    利用TCP/IP的堆栈指纹的方法
  • 原文地址:https://www.cnblogs.com/Blogwj123/p/15766297.html
Copyright © 2011-2022 走看看