zoukankan      html  css  js  c++  java
  • django -- cookie和session

    前戏

    我们在访问一些网站的时候,如果没有登录就会跳转到登录页面,如果是登录了,才会让我们访问,那服务器是怎么知道我们有没有登录呢?这就涉及到了Cookie,大家都知道HTTP的特点,无状态。也就是浏览器发送到服务器的每个请求都是没有关系的。这时候就要给服务器设置一个Cookie,下次浏览器请求的时候,携带这个Cookie,如果有携带,那服务器就认为是登录的,如果没有携带或错误,那浏览器就跳转到登录页面。

    什么是Cookie呢?

    Cookie是指一小段信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对。Cookie的工作原理是由服务器产生内容,浏览器收到请求后保存在本地,当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie判断当前用户是哪个了

    Cookie初识

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="{{ request.get_full_path }}" method="post">
        {% csrf_token %}
        用户名:
        <input type="text" name="username">
        密码:
        <input type="text" name="pwd">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    login.html

    我们写三个视图函数,login,home和index

    from django.shortcuts import render,redirect,HttpResponse
    from appTest01 import models
    
    # Create your views here.
    
    
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('username')
            password = request.POST.get('pwd')
            if models.Person.objects.filter(name=user, pwd= password):
    
                return redirect('/index/')
        return render(request,'login.html')
    
    def index(request):
        return HttpResponse('index')
    
    def home(request):
        return HttpResponse('home')

    上面这样的写法,我们可以直接通过路径访问对应的页面,不需要登录,当然不符合我们的需求,那我们给加上Cookie

    from django.shortcuts import render,redirect,HttpResponse
    from appTest01 import models
    
    # Create your views here.
    
    
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('username')
            password = request.POST.get('pwd')
            if models.Person.objects.filter(name=user, pwd= password):
                ret = redirect('/index/')
                ret.set_cookie('is_login','yes')
                return ret
    
        return render(request,'login.html')
    
    def index(request):
        print(request.COOKIES,type(request.COOKIES))  查看cookie
        return HttpResponse('index')
    
    def home(request):
        return HttpResponse('home')

    我们使用set_cookie()来设置Cookie,然后我们输入账号密码去登录,查看cookie

    我们可以使用 request.COOKIES来查看cookie,

    request.COOKIES,type(request.COOKIES)

    结果:

    {'csrftoken': 'pB5vZxQOwWnvNyw13S0ImpbInxOpnIV0BsAcE31hCHLOP3EIMM8veLpxIlcRBYIg', 'is_login': 'yes'} <class 'dict'>

    既然它是一个字典类型的,我们就可以拿到cookie,然后在进行一个判断,在来改写视图函数

    from django.shortcuts import render,redirect,HttpResponse
    from appTest01 import models
    
    # Create your views here.
    
    
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('username')
            password = request.POST.get('pwd')
            if models.Person.objects.filter(name=user, pwd = password):
                ret = redirect('/index/')
                ret.set_cookie('is_login','yes')
                return ret
        return render(request,'login.html')
    
    def index(request):
        if request.COOKIES.get('is_login') == 'yes':  # 获取我们设置的Cookie
            return HttpResponse('index')
        return redirect('/login/')
    
    def home(request):
        if request.COOKIES.get('is_login') == 'yes':
            return HttpResponse('home')
        return redirect('/login/')

    上面代码我们就实现了我们的需求,如果登录成功,可以访问index和home页面,如果没有登录,则返回login页面,那试想一下,以后我们的项目页面有几百个,难道要给每个页面都要写判断吗?这样肯定是不行的,我们可以用装饰器来实现这种需求,代码如下

    from django.shortcuts import render, redirect, HttpResponse
    from appTest01 import models
    
    
    # Create your views here.
    
    def login_cookie(f):
        def inner(request, *args, **kwargs):
            if request.COOKIES.get('is_login') == 'yes':  # 获取我们设置的Cookie,如果通过,执行被装饰的函数
                res = f(request, *args, **kwargs)
                return res
            return redirect('/login/')
    
        return inner
    
    
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('username')
            password = request.POST.get('pwd')
            if models.Person.objects.filter(name=user, pwd=password):
                ret = redirect('/index/')
                ret.set_cookie('is_login', 'yes')
                return ret
        return render(request, 'login.html')
    
    
    @login_cookie
    def index(request):
        return HttpResponse('index')
    
    
    @login_cookie
    def home(request):
        return HttpResponse('home')

    但是这样又有个问题,如果我们没有登录访问home页面,它会跳转到登录页面,我们正确登录之后返回到了index页面,这肯定不是我们需要的效果,因为我们在login函数里已经写死了,登录成功之后返回的是index页面,我们来看下京东没登录时点击“我的京东”是怎样处理的

    我们可以看到,京东在登录页面后面加了个参数,然后登录成功之后,直接跳转到后面的那个参数页面了,那我们在来修改我们的代码

    from django.shortcuts import render, redirect, HttpResponse
    from appTest01 import models
    
    
    # Create your views here.
    
    def login_cookie(f):
        def inner(request, *args, **kwargs):
            current_url = request.path_info  # 获取地址中?后面的参数
            print('current_url为:', current_url)
            if request.COOKIES.get('is_login') == 'yes':
                res = f(request, *args, **kwargs)
                return res
            return redirect('/login/?returnurl={}'.format(current_url))  # 拼接url路径
    
        return inner
    
    
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('username')
            password = request.POST.get('pwd')
            if models.Person.objects.filter(name=user, pwd=password):
                url_parameter = request.GET.get('returnurl')  # 获取当前路径里的returnurl参数
                ret = redirect(url_parameter)  # 返回到returnurl页面
                ret.set_cookie('is_login', 'yes')
                return ret
        return render(request, 'login.html')
    
    
    @login_cookie
    def index(request):
        return HttpResponse('index')
    
    
    @login_cookie
    def home(request):
        return HttpResponse('home')

    结果:

    如果你在未登录状态下访问home页面,current_url就为/home/
    如果你在未登录状态下访问index页面,current_url就为/index/

    那么问题又来了,如果我们直接访问login页面,登录成功则会报错,这是因为当前的 url_parameter 参数为空,只需要修改login函数里的东西就可以了

    def login(request):
        if request.method == 'POST':
            user = request.POST.get('username')
            password = request.POST.get('pwd')
            if models.Person.objects.filter(name=user, pwd=password):
                url_parameter = request.GET.get('returnurl')  # 获取当前路径里的returnurl参数
                if url_parameter:  # 如果有值
                    ret = redirect(url_parameter)  # 返回到returnurl页面
                else:  # 如果为空
                    ret = redirect('/home/')
                ret.set_cookie('is_login', 'yes')
                return ret
        return render(request, 'login.html')

    设置和获取Cookie

    在上面的例子中,我们是使用 set_cookie()来进行设置Cookie,还有另一种方式

    rep = HttpResponse(...)
    rep = render(request, ...)
    
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)

    获取Cookie就不能使用request.COOKIES[’key‘]或者request.COOKIES.get('key')的方法获取了,要使用如下的方法获取

    request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None)

    get_signed_cookie方法的参数:

    • default: 默认值
    • salt: 加密盐
    • max_age: 后台控制过期时间

    删除Cookie

    删除Cookie使用delete_cookie('key')

    def loginout(request):
        res = redirect('/login/')
        res.delete_cookie('is_login')  # 删除我们设置的is_login的cookie
        return res

    Cookie的其他参数

    1. key,键
    2. value='' 值
    3. max_age=xx   超时时间,xx为一个int型的,单位为秒,如xx=60,则cookie的有效期为60秒
    4. path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
    5. domain=None, Cookie生效的域名
    6. secure=False, https传输
    7. httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

     Session

    Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。

    问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。

    我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。

    设置session

    我们只需要把上面设置cookie和设置session的代码改下11,30,48行就可以了

     1 from django.shortcuts import render, redirect, HttpResponse
     2 from appTest01 import models
     3 
     4 
     5 # Create your views here.
     6 
     7 def login_cookie(f):
     8     def inner(request, *args, **kwargs):
     9         current_url = request.path_info  # 获取地址中?后面的参数
    10         print('current_url为:', current_url)
    11         # if request.COOKIES.get('is_login') == 'yes':
    12         if request.session.get('is_login') == 'yes':  # 获取session
    13             res = f(request, *args, **kwargs)
    14             return res
    15         return redirect('/login/?returnurl={}'.format(current_url))  # 拼接url路径
    16 
    17     return inner
    18 
    19 
    20 def login(request):
    21     if request.method == 'POST':
    22         user = request.POST.get('username')
    23         password = request.POST.get('pwd')
    24         if models.Person.objects.filter(name=user, age=password):
    25             url_parameter = request.GET.get('returnurl')  # 获取当前路径里的returnurl参数
    26             if url_parameter:  # 如果有值
    27                 ret = redirect(url_parameter)  # 返回到returnurl页面
    28             else:  # 如果为空
    29                 ret = redirect('/home/')
    30             # ret.set_cookie('is_login', 'yes',max_age=5)
    31             request.session['is_login']='yes'  # 设置session
    32             return ret
    33     return render(request, 'login.html')
    34 
    35 
    36 @login_cookie
    37 def index(request):
    38     return render(request, 'index.html')
    39 
    40 
    41 @login_cookie
    42 def home(request):
    43     return HttpResponse('home')
    44 
    45 
    46 def loginout(request):
    47     res = redirect('/login/')
    48     # res.delete_cookie('is_login')  # 删除我们设置的is_login的cookie
    49     request.session.delete() # 删除session
    50     return res

    session会默认存在django_session这张表里

    你去浏览器查看cookie会发现,这时浏览器保存的key不在是is_login了,而是sessionid,value也不在是yes了,而是数据库里存的session_key,当浏览器在次发请求时,Django会去django_session表里查询有没有对应的这个value,如果有,则认为登录过

    session的其他方法

    # 获取、设置、删除Session中数据
    request.session['k1']  # 获取key,找不到会报错
    request.session.get('k1',None)  # 获取key,找不到为None
    request.session['k1'] = 123 # 设置session
    request.session.setdefault('k1',123) # 设置,如果存在k1则不设置
    del request.session['k1']  # 删除k1的session
    
    
    # 所有 键、值、键值对
    request.session.keys()  # 获取所有的key
    request.session.values()  # 获取所有的value
    request.session.items()  # 获取所有的key和value
    request.session.iterkeys()  # 生成器类型的key
    request.session.itervalues()  # 生成器类型的value
    request.session.iteritems()
    
    # 会话session的key
    request.session.session_key  # 获取数据库里存的那个session_key的值
    
    # 将所有Session失效日期小于当前日期的数据删除
    request.session.clear_expired()
    
    # 检查会话session的key在数据库中是否存在
    request.session.exists("session_key")  # 布尔值,存在返回True
    
    # 删除当前会话的所有Session数据
    request.session.delete()  # 浏览器里的sessionid还存在,只是删除了数据库里的数据
      
    # 删除当前的会话数据并删除会话的Cookie。
    request.session.flush() 
        这用于确保前面的会话数据不可以再次被用户的浏览器访问
        例如,django.contrib.auth.logout() 函数中就会调用它。
    
    # 设置会话Session和Cookie的超时时间
    request.session.set_expiry(value)
        * 如果value是个整数,session会在些秒数后失效。
        * 如果value是个datatime或timedelta,session就会在这个时间后失效。
        * 如果value是0,用户关闭浏览器session就会失效。
        * 如果value是None,session会依赖全局session失效策略。

    session配置

    from django.conf import global_settings
    
    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,默认修改之后才保存(默认)

     总结:

    1. cookie
      1. cookie是什么?
        保存在浏览器上一组组键值对
      2. 为什么要有cookie?
        http协议是无状态,每次请求都是无关联的,没有办法保存状态。
        使用cookie保存状态。
      3. django的操作cookie
        3.1. 设置cookie
          ret = HttpResponse('xxx')
          ret.set_cookie(key,value,max_age=5)
          ret.set_signed_cookie(key,value,max_age=5,salt='xxx')

        3.2. 获取cookie
          request.COOKIES['is_login']
          request.COOKIES.get('is_login')
          request.get_signed_cookie(key,salt='xxx',default='')

        3.3. 删除cookie

          ret.delete_cookie(key)

    2. session
      1. session是什么?
        保存在服务器上一组组键值对,依赖cookie

      2. 为什么要用session?
        2.1. cookie保存在浏览器上 不安全
        2.2. cookie的长度受到限制

      3. django中操作session
        3.1. 设置session
          request.session[key] = value
          request.session.setdefault(key,value)


        3.2. 获取session
          request.session[key]
          request.session.get(key)

        3.3. 删除session
          del request.session[key] ——》删除某一个键值对
          request.session.delete() ——》 删除该用户的所有的session数据,不删除cookie
          request.session.flush() ——》 删除该用户的所有的session数据,删除cookie


      4. 设置超时时间
        request.session.set_expiry()

      5. 清除所有过期的session
        request.session.clear_expired()

  • 相关阅读:
    HDU 1069 Monkey and Banana
    HDU 1029 Ignatius and the Princess IV
    HDU 1024 Max Sum Plus Plus
    Gym100923H Por Costel and the Match
    Codeforces 682C Alyona and the Tree
    Codeforces 449B Jzzhu and Cities
    Codeforces (ccpc-wannafly camp day2) L. Por Costel and the Semipalindromes
    Codeforces 598D (ccpc-wannafly camp day1) Igor In the Museum
    Codeforces 1167c(ccpc wannafly camp day1) News Distribution 并查集模板
    快乐数问题
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/11241155.html
Copyright © 2011-2022 走看看