9.djang -- cookie和session

djang -- cookie和session

一.cookie -- 小甜点

1.由来

http协议,两个特点: 无状态、无连接(http//1.1版本后短连接)
	无状态:  -- http协议不会记录客户端和服务端的任何状态信息,每次请求都是独立的,导致不能维持会话
	状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。
	访问哪一个网址,都要验证用户的身份,但是还有保证什么呢,用户登陆过之后,还要保证登陆了的用户不需要再重复登陆,就能够访问我网站的其他的网址的页面,对不对,但是http无状态啊,怎么保证这个事情呢?此时就要找cookie了。

2.什么是cookie

	cookie是浏览器的技术,Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,可以理解为服务端给客户端的一个小甜点,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

3.cookie原理

	cookie的工作原理是:浏览器第一次访问服务端,带着一个空的cookie,然后由服务器产生内容,浏览器收到相应后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。

4.基于cookie的登陆认证

路由:urls.py

from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login, name='login'),
    url(r'^home/', views.home,name='home'),
    url(r'^person/', views.person,name='person'),
]

视图:views.py -- 写cookie登陆认证

from django.shortcuts import render,redirect

def login(request):

    if request.method == 'GET':
        return render(request,'login.html')
    else:
        uname = request.POST.get('username')
        pwd = request.POST.get('password')
        if uname == 'jia' and pwd == '123': # 用户名密码输入正确才添加cookie
            ret = redirect('home')
            # ret.set_cookie('is_login',True) #设置cookie键值对
            ret.set_cookie('is_login',True,5) #设置cookie数据5秒后清除
            ret.set_cookie('uname', uname) #可以设置多个值

            return ret
            # 浏览器响应头中有Set-Cookie: is_login=True;显示cookie数据
        else:
            return redirect('login')

def home(request): # 我们要求:没有登陆,不能直接访问home页面

    print(request.COOKIES)
    # 可以拿到本次访问携带的cookie字典数据
    # {'is_login': 'True', 'uname': 'jia'}
    # 网络传输 -- bytes类型数据(编码处理) -- 所以值都是字符串了

    # 基于cookie的登录认证(判断用户是否处于登录状态)
    is_login = request.COOKIES.get('is_login')
    # cookie中有登录成功之后的标识信息才能正常访问home页面
    # 不然就让它去login页面登录
    if is_login == 'True':
        return render(request,'home.html')
    else:
        return redirect('login')

templates目录下HTML文件:

login.html

<body>
<form action="" method="post">
    用户名: <input type="text" name="username">
    密码: <input type="password" name="password">
    <input type="submit">
</form>
</body>

home.html

<body>
<h1>这是首页</h1>
<a href="{% url 'person' %}">个人中心</a>
</body>

5.cookie登录认证装饰器

视图:views.py ,其他同上

from django.shortcuts import render,redirect,HttpResponse

# 基于cookie的登录认证装饰器
def outer(func):
    def inner(request,*args,**kwargs):
        is_login = request.COOKIES.get('is_login')
        if is_login == 'True':
            res = func(request,*args,**kwargs)
            return res
        else:
            return redirect('login')
    return inner

@outer  # 访问其他页面时登陆认证加装饰器
def person(request):
    return render(request,'person.html')

@outer
def home(request):
    return render(request, 'home.html')

def login(request):

    if request.method == 'GET':
        return render(request,'login.html')
    else:
        uname = request.POST.get('username')
        pwd = request.POST.get('password')
        if uname == 'jia' and pwd == '123': # 用户名密码输入正确才添加cookie
            ret = redirect('home')
            # ret.set_cookie('is_login',True) #设置cookie键值对
            ret.set_cookie('is_login',True,5) #设置cookie数据5秒后清除
            ret.set_cookie('uname', uname) #可以设置多个值

            return ret
            # 浏览器响应头中有Set-Cookie: is_login=True;显示cookie数据
        else:
            return redirect('login')

6.django中操作cookie

设置cookie
rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...) #包含添加和修改,键和值
# 设置签名cookie --  
# rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)

获取cookie
request.COOKIES.get('is_login')
request.COOKIES['key']
# 获取签名cookie
# request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

删除cookie
def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 删除用户浏览器上之前设置的usercookie值
    return rep

7.Set_cookie方法

class HttpResponseBase:

        def set_cookie(self, 
   key,            键
   value='',       值
   max_age=None,   有效时间,max_age=20意思是这个cookie20秒后就消失了,默认时长是2周,这个是以秒为单位的,cookie需要延续的时间(以秒为单位),如果参数是 None`` ,这个cookie会延续到浏览器关闭为止。

   expires=None,   有效时间,值是一个datetime类型的时间日期对象,到这个日期就失效的意思,用的不多,expires默认None ,cookie失效的实际日期/时间。 
                                

   path='/',       指定Cookie生效的路径,就是访问哪个路径可以得到cookie,'/'是所有路径都能获得cookie,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。 / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
                     
   domain=None,    Cookie生效的域名,你可用这个参数来构造一个跨站cookie。
                   如, domain=".example.com",所构造的cookie对下面这些站点都是可读的:
                      www.example.com 、 www2.example.com
                   如果该参数设置为 None ,cookie只能由设置它的站点读取。

   secure=False,   如果设置为 True ,浏览器将通过HTTPS来回传cookie。HTTP不生效
   httponly=False  如果为True,只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
               	): pass

8.cookie设置中文时的编码问题:(了解)

  • 所以尽量不要出现中文

cookie在设置时不允许出现中文。非要设置中文的怎么办,看下面的解决方案:

# 方式1
def login(request):

    ret = HttpResponse('ok')
    
    ret.set_cookie('k1','你好'.encode('utf-8').decode('iso-8859-1'))
    
    #取值:request.COOKIES['k1'].encode('utf-8').decode('iso-8859-1').encode('iso-8859-1').decode('utf-8')

    return ret

方式2 json

def login(request):

    ret = HttpResponse('ok')
    
    import json

    ret.set_cookie('k1',json.dumps('你好'))
    #取值 json.loads(request.COOKIES['k1'])
    return ret

9.Cookie规范

  • Cookie大小上限为4KB;
  • 一个服务器最多在客户端浏览器上保存20个Cookie;
  • 一个浏览器最多保存300个Cookie,因为一个浏览器可以访问多个服务器。

    上面的数据只是HTTP的Cookie规范,但在浏览器大战的今天,一些浏览器为了打败对手,为了展现自己的能力起见,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现把你硬盘占满的可能!
注意,不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。

10.cookie的缺点:

1 存储数据的大小有上限
2 明文存储数据 (不安全,敏感数据尽量不要通过cookie存储)

为了解决cookie的弊端,session技术出现了

二.session

1.简介:

 Session是服务器端技术,Django的session技术是基于cookie实现的,利用这个技术,服务器在运行时可以 为每一个用户的浏览器创建一个其独享的session对象,
cookie缺点:
    1 存储数据的大小有上限
    2 明文存储数据 (数据储存在客户端浏览器,不安全,敏感数据尽量不要通过cookie存储)
session优点:
    1.数据存在服务端,比较安全,存储大小无上限
    2.传输效率也高,cookie中只有一对随机字符串
    
问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。

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

  总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。

  另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

2.django操作session

基于session的登录认证

视图:views.py -- 其他页面与cookie一样

from django.shortcuts import render,redirect,HttpResponse

# 基于session的登录认证装饰器
def outer(func):
    def inner(request,*args,**kwargs):
        is_login = request.session.get('is_login')
        if is_login:
            res = func(request,*args,**kwargs)
            return res
        else:
            return redirect('login')
    return inner

def login(request):

    if request.method == 'GET':
        return render(request,'login.html')
    else:
        uname = request.POST.get('username')
        pwd = request.POST.get('password')
        if uname == 'jia' and pwd == '123':
            ret = redirect('home')
            # 以键值方式设置session
            request.session['is_login'] = True
            request.session['uname'] = uname
            '''
                1 生成随机字符串asdf,放到cookie中(sessionid:asdf)
                2 在数据库表(django-session,先进行数据库同步指令)中,
                    数据表中有三个字段: 
                        data = 字段序列化然后加密is_login和uname数据
                        session_key    --> asdf 随机字符串
                        session_data   --> data 加密数据
                        session_expire --> 默认两周 有效时间
            '''
            return ret
        else:
            return redirect('login')

@outer  #加session登陆认证装饰器
def person(request):
    return render(request, 'person.html')

def home(request):

    # 获取session
    is_login = request.session.get('is_login')
    '''
        1 取出本次cookie中的sessionid对应的值asdf随机字符串
        2 拿着asdf随机字符串去django-session表中获取保存的那条记录
        3 将该记录中的session_data进行解密并反序列化,然后取出is_login键对应的值
    '''
    print(is_login, type(is_login))  # True <class 'bool'>
    if is_login:
        return render(request, 'home.html')
    else:
        return redirect('login')
session的基本操作
# 1.取值
request.session['k1'] 
request.session.get('k1',None) #request.session这句是帮你从cookie里面将sessionid的值取出来,将django-session表里面的对应sessionid的值的那条记录中的session-data字段的数据给你拿出来(并解密),get方法就取出k1这个键对应的值

# 2.设置值
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置

# 3.删除值,删除某个键值对
del request.session['k1']  #django-session表里面同步删除

# 4.所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()

# 5.会话session的key
session_key = request.session.session_key  获取sessionid的值

# 6.将所有Session失效日期小于当前日期的数据删除,将过期的删除
request.session.clear_expired()

# 7.检查会话session的key在数据库中是否存在
request.session.exists("session_key") #session_key就是那个sessionid的值

# 8.删除当前会话的所有Session数据
request.session.delete()

# 9.删除当前的会话数据并删除会话的Cookie。
request.session.flush()   # 删除cookie中的sessionid值,并且同步删除数据库的记录

# 10.设置会话Session和Cookie的有效期设置
request.session.set_expiry(value)
    * 如果value是个整数,session会在些秒数后失效。
    * 如果value是个datatime或timedelta,session就会在这个时间后失效。
    * 如果value是0,用户关闭浏览器session就会失效。
    * 如果value是None,session会依赖全局session失效策略。

一个服务端对应一个浏览器(一个页面只能登陆一个用户),只有一个sessionid

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,默认修改之后才保存(默认)
原文地址:https://www.cnblogs.com/jia-shu/p/14589832.html