• cookie和session


    一 cookie与session

    1.1发展史   

      1.网站都没有保存用户功能的需求 所有用户访问返回的结果都是一样的 eg:新闻、博客、文章...

      2.出现了一些需要保存用户信息的网站 eg:淘宝、支付宝、京东...

      以登陆功能为例:如果不保存用户登陆状态 也就意味着用户每次访问网站都需要重复的输入用户名和密码(你觉得这样的网站你还想用吗?)
      当用户第一次登陆成功之后 将用户的用户名密码返回给用户浏览器 让用户浏览器保存在本地,之后访问网站的时候浏览器自动将保存在浏览器上的用户名和密码发送给服务端,服务端获取之后自动验证
      早起这种方式具有非常大的安全隐患

      优化:
      当用户登陆成功之后,服务端产生一个随机字符串(在服务端保存数据,用kv键值对的形式),交由客户端浏览器保存
      随机字符串1:用户1相关信息  随机字符串2:用户2相关信息
      之后访问服务端的时候,都带着该随机字符串,服务端去数据库中比对是否有对应的随机字符串从而获取到对应的用户信息
      但是如果你拿到了截获到了该随机字符串,那么你就可以冒充当前用户 其实还是有安全隐患的

    1.2 介绍 

      cookie:服务端保存在客户端浏览器上的信息都可以称之为cookie,它的表现形式一般都是k:v键值对(可以有多个)
      session:数据是保存在服务端的并且它的表现形式一般也是k:v键值对(可以有多个)
      token:session虽然数据是保存在服务端的 但是禁不住数据量大,服务端不再保存数据
        登陆成功之后 将一段用户信息进行加密处理(加密算法之后你公司开发知道)
        将加密之后的结果拼接在信息后面 整体返回给浏览器保存
        浏览器下次访问的时候带着该信息 服务端自动切去前面一段信息再次使用自己的加密算法
        跟浏览器尾部的密文进行比对
      jwt认证:三段信息(后期会讲 结合django一起使用)

      总结:
      1.cookie就是保存在客户端浏览器上的信息
      2.session就是保存在服务端上的信息
      3.session是基于cookie工作的(其实大部分的保存用户状态的操作都需要使用到cookie)

    二 Cookie操作

      虽然cookie是服务端告诉客户端浏览器需要保存内容,但是客户端浏览器可以选择拒绝保存 如果禁止了 那么 只要是需要记录用户状态的网站登陆功能都无法使用了

      如果你想要的使用cookie那必须写成下面的形式

    obj1 = HttpResponse()
    # 操作cookie
    return obj1
    
    obj2 = render()
    # 操作cookie
    return obj2
    
    obj3 = redirect()
    # 操作cookie
    return obj3

      操作cookie的方式

    #设置cookie
    obj.set_cookie(key,value)
    # 加盐
    obj.set_signed_cookie(key,value,salt='')
    #获取cookie
    request.COOKIES.get(key)
    request.get_signed_cookie(key,salt='')
    #在设置cookie的时候可以添加一个超时时间
    obj.set_cookie('username', 'jason666',max_age=3,expires=3)
    max_age
    expires
    ‘’‘
    两者都是设置超时时间的 并且都是以秒为单位
    需要注意的是 针对IE浏览器需要使用expires
    主动删除cookie(注销功能)
    ‘’’

      案例:用户如果在没有登陆的情况下想访问一个需要登陆的页面,那么先跳转到登陆页面,当用户输入正确的用户名和密码之后,应该跳转到用户之前想要访问的页面去 而不是直接写死

    def login_auth(func):
        def inner(request,*args,**kwargs):
            target_url = request.get_full_path()# 能够获取到用户上一次想要访问的url
            if request.COOKIES.get('username'):
                return func(request,*args,**kwargs)
            else:
                return redirect('/login/?next=%s'%target_url)
        return inner
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'jason' and password == '123':
                # 获取用户上一次想要访问的url
                target_url = request.GET.get('next')  # 这个结果可能是None
                if target_url:
                    obj = redirect(target_url)
                else:
                    # 保存用户登陆状态
                    obj = redirect('/home/')
                # 让浏览器记录cookie数据
                obj.set_cookie('username', 'jason666')
                """
                浏览器不单单会帮你存
                而且后面每次访问你的时候还会带着它过来
                """
                # 跳转到一个需要用户登陆之后才能看的页面
                return obj
        return render(request,'login.html')
    
    
    @login_auth
    def home(request):
        return HttpResponse("我是home页面,只有登陆的用户才能进来哟~")

    三 session操作

      session数据是保存在服务端的(存?),给客户端返回的是一个随机字符串   sessionid:随机字符串

      在默认情况下操作session的时候需要django默认的一张django_session表

      数据库迁移命令django会自己创建很多表 django_session就是其中的一张

      django默认session的过期时间是14天但是你也可以人为的修改它

      操作session的方式

    #设置session    
    request.session['key'] = value
    
    #获取session
    request.session.get('key')
    
    #设置过期时间
    request.session.set_expiry()
    '''
    括号内可以放四种类型的参数
    1.整数    多少秒
    2.日期对象    到指定日期就失效
    3.0        一旦当前浏览器窗口关闭立刻失效
    4.不写    失效时间就取决于django内部全局session默认的失效时间
    '''
    
    #清除session    
    request.session.delete()  # 只删服务端的 客户端的不删
    request.session.flush()  # 浏览器和服务端都清空(推荐使用)

      设置和获取分析

    request.session['hobby'] = 'girl'
        """
        内部发送了那些事
            1.django内部会自动帮你生成一个随机字符串
            2.django内部自动将随机字符串和对应的数据存储到django_session表中
                2.1先在内存中产生操作数据的缓存
                2.2在响应结果django中间件的时候才真正的操作数据库
            3.将产生的随机字符串返回给客户端浏览器保存
        """

    request.session.get('hobby') """ 内部发送了那些事 1.自动从浏览器请求中获取sessionid对应的随机字符串 2.拿着该随机字符串去django_session表中查找对应的数据 3.如果比对上了 则将对应的数据取出并以字典的形式封装到request.session中 如果比对不上 则request.session.get()返回的是None """

      案例:用户如果在没有登陆的情况下想访问一个需要登陆的页面,那么先跳转到登陆页面,当用户输入正确的用户名和密码之后,应该跳转到用户之前想要访问的页面去 而不是直接写死

    def login_auth(func):
        def inner(request,*args,**kwargs):
            target_url = request.get_full_path()# 能够获取到用户上一次想要访问的url
            if request.session.get('aaa'):
                return func(request,*args,**kwargs)
            else:
                return redirect('/login/?next=%s'%target_url)
        return inner
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'jason' and password == '123':
                # 获取用户上一次想要访问的url
                target_url = request.GET.get('next')  # 这个结果可能是None
                if target_url:
                    obj = redirect(target_url)
                else:
                    # 保存用户登陆状态
                    obj = redirect('/home/')
                # 让浏览器记录session数据
                request.session['aaa'] = 'aaa'
                # 跳转到一个需要用户登陆之后才能看的页面
                return obj
        return render(request, 'login.html')
    
    @login_auth
    def home(request):
        return HttpResponse("我是home页面,只有登陆的用户才能进来哟~")

      session是保存在服务端的 但是session的保存位置可以有多种选择
      1.MySQL
      2.文件
      3.redis
      4.memcache

      django_session表中的数据条数是取决于浏览器的,同一个计算机上(IP地址)同一个浏览器只会有一条数据生效,主要是为了节省服务端数据库资源
      (当session过期的时候可能会出现多条数据对应一个浏览器,但是该现象不会持续很久,内部会自动识别过期的数据清除 你也可以通过代码清除)

    四 CBV如何添加装饰器

    from django.views import View
    from django.utils.decorators import method_decorator
    """
    CBV中django不建议你直接给类的方法加装饰器
    无论该装饰器能都正常给你 都不建议直接加
    """
    
    # @method_decorator(login_auth,name='get')  # 方式2(可以添加多个针对不同的方法加不同的装饰器)
    # @method_decorator(login_auth,name='post')
    class MyLogin(View):
        @method_decorator(login_auth)  # 方式3:它会直接作用于当前类里面的所有的方法
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
        # @method_decorator(login_auth)  # 方式1:指名道姓
        def get(self,request):
            return HttpResponse("get请求")
    
        def post(self,request):
            return HttpResponse('post请求')
  • 相关阅读:
    java系列: 在eclipse中调试时,输入的jsp或者servlet页面的地址要区分大小写
    Activiti系列: 如何在web中使用activiti和sql server
    Java系列:Add Microsoft SQL JDBC driver to Maven
    eclipse系列: Cannot change version of project facet Dynamic web的解决方法
    Java系列:报错信息The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
    Activiti系列:如何让Activiti-Explorer使用sql server数据库
    MySQL系列:查看并修改当前数据库的编码
    activiti-explorer:使用mysql导入外部bpmn文件后存在乱码的问题
    Activiti系列:如何把Activiti工程转换为maven工程以解决依赖项找不到的问题
    java从0开始学——数组,一维和多维
  • 原文地址:https://www.cnblogs.com/bk134/p/13050329.html
Copyright © 2020-2023  润新知