Flask的cookie、session

七、设置cookies

from flask import Flask, make_response

app = Flask(__name__)
app.debug = True


@app.route('/', methods=['POST', 'GET'])
def index():
    # 响应头,添加make_response
    response = make_response('ok')
    
    # 设置cookies
    response.set_cookie('key', 'val')  
	
    # 删除cookies
    response.delete_cookie("key")
    
    # 设置响应头
    response.headers["x-somexx"] = "A SB"
    
    return response


if __name__ == '__main__':
    app.run()

7.1 设置cookie的参数

再设置cookie的调用set_cookie()时候传入关键字实参 max_age= 值,这个代表多少秒后过期。

注意:max_age参数设置过期时间不兼容IE8一下的浏览器

...
@app.route('/')
def hello_world():
    resp = Response('设置cookie给浏览器')
    resp.set_cookie('user_name', 'mark',max_age=60)
    
    
    # expires = datetime.now()+timedelta(days=30, hours=16)
    # resp.set_cookie('user_name', 'mark', expires=expires)  # 一个月过期时间
    
    return resp
...

参数

key, 键
value='', 值
max_age=None, 超时时间 cookie需要延续的时间(以秒为单位)如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止

expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
                   
path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
                   
domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
                   
secure=False, 浏览器将通过HTTPS来回传cookie
                   
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

7.2 查询cookie

查询cookie 是通过请求对象的cookies属性读取,读取的过程是使用设置cookie时的key来读取到设置cookievalue

...
@app.route('/get_cookie/')
def get_cookie():
    user_name = request.cookies.get('user_name')
    if user_name == 'mark':
        return '{}的信息'.format(user_name)

    return 'cookie验证失败'
...

八、flask的session

session的基本概念:session又称之为安全的cookie,session是一个思路、是一个概念、一个服务器存储授权信息的解决方案,不同的服务器,不同的框架,不同的语言有不同的实现,session的目的和cookie完全一致,cookie在客户端和服务端处理的非常粗糙,cookie在浏览器保存的时候以及传输的过程均使用明文,导致了很多安全隐患问题,session的出现就是为了解决cookie存储数据不安全的问题。

注意:session是一个思路一个概念,session的实现是基于cookie的,session并不像cookie是一项真实存在的技术,可以简单的理解为把粗糙的cookie在服务端通过加密,永久化等方式提高cookie的安全级别。

实现session的两种思路

第一种

  1. 客户端携带用户信息请求服务端验证。
  2. 服务端验证成功后生成随机的session_id与用户信息建立映射后存储到数据库中(注意:数据库可以是任意永久化保存数据的机制,如redis、memcached、mysql、甚至是文件等等)。
  3. 服务端把刚刚生成的session_id作为cookie信息返回给客户端。
  4. 客户端收到以session_id为内容的cookie信息保存到本地。
  5. 客户端再次请求的时候会携带以session_id为内容的cookie去访问服务端,服务端取出session_id去数据库校验得到用户信息。
  6. 1550917260707

第二种(flask使用方式)

  1. 客户端携带用户信息请求服务端验证。
  2. 服务端收到用户信息验证成功后,服务端再把用户信息经过严格的加密加盐生成session信息。并且把刚刚生成的session信息作为cookie的内容返回给客户端。
  3. 客户端收到以session信息为内容的cookie保存到本地。
  4. 客户端再次请求的时候会携带以session信息为内容的cookie去访问服务端,服务端取出session信息经过解密得到用户的信息。

1550918351048

注意:flask使用的就是第二种思路,利用加密解密的方式实现session,实现安全的cookie,服务端并不会做永久化的储存。

cookie:存放在客户端的键值对
session:存放在客户端的键值对
token:存放在客户端,通过算法来校验

8.1 设置session(使用版)

Flask提供了session对象用来将cookie加密储存,session通过秘钥对数据进行签名以加密数据。

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24) # 配置session使用的秘钥

@app.route('/')
def set_session_info():
    session['username'] = 'mark' # 使用用户信息配置sesion信息作为cookie,并添加到响应体中
    
    return '设置session信息'

session对象像可以字典一样操作,内部是把字典的信息进行加密操作然后添加到相应体中作为cookie,响应的时候会自动返回给浏览器。

 session['username'] = 'mark'
 session['userphone'] = '123456'  # 可以指定多条session信息,统一放到响应的cookie中返回给浏览器

8.2 设置session(分析版)

在使用session之前必须现在设置一下密钥

app.secret_key="asdas" # 值随便
# app.config['SECRET_KEY'] = os.urandom(24) # 配置session使用的秘钥
设置:session['username'] = 'xxx'
# 在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
# 在flask中他没有数据库,但session是怎样实现的?
	# 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
    # 我们通过app.session_interface来查看
    
删除:session.pop('username', None)
from flask import Flask,session

app = Flask(__name__)
# 要用session,必须app配置一个密钥
app.secret_key  =  "asdasdihasdiuh"

# 设置session的名字,默认配置文件中为:session
app.config['SESSION_COOKIE_NAME']="python13session" 

# app.session_interface

#app.session_interface实现了两个方法,一个叫save_session,一个open_session,
# save_session 存session执行,加密设置cookies
# open_session 取session执行,解密大字典,拿到session
@app.route("/",)
def index():
    #如何设置sessoion
    # 1 导入session
    # 2 给sessoion设置值
    session['name'] = "egon"
    return "ok"

@app.route("/login")
def login():
    print(session["name"])
    return "login"

if __name__ == '__main__':
    app.run()
    

8.3 设置session有效期

后端Flask跟浏览器交互默认情况下,session cookie会在用户关闭浏览器时清除。通过将session.permanent属性设为True可以将session的有效期延长为31天,也可以通过操作app的配置PERMANENT_SESSION_LIFETIME来设置session过期时间。

案例 3.3.2.1:开启指定session过期时间模式

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)


@app.route('/')
def set_session_info():
    session['username'] = 'mark'
    session['userphone'] = '123456'
    session.permanent = True # 开启设置有效期,默认为31天后过期
    return 'Hello World!'
...

设置自定义过期时间

# 通过设置PERMANENT_SESSION_LIFETIME指定具体的过期时间

from datetime import timedelta
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1) # 设置为1小时候过期

8.4 获取sessoin

在Flask中获取设置的session信息通过session对象获取,session对象是继承了字典类,所以获取的时候是字典的取值方式。其内部会把浏览器传过来的session信息解密。

@app.route('/get_session/')
def get_session():
    username = session.get('username')
    userphone = session.get('userphone')
    if username or userphone:
        return "{},{}".format(username, userphone)
    return "session为空"

1550930691065

8.5 删除session

session对象调用pop()可以根据具体的session的key清除掉指定的session信息。

session对象调用clear()可以清除此次请求的浏览器关于本域名的所有session信息

@app.route('/del_session/')
def del_session():
    session.pop('username')
    # session.clear()
    return '删除成功'

8.6 源码分析

session源码的执行流程

-save_seesion
    -响应的时候,把session中的值加密序列化放大到了cookie中,返回到浏览器中
-open_session
    -请求来了,从cookie中取出值,反解,生成session对象,以后再视图函数中直接用sessoin就可以了。

源码分析

# app.session_interface  点进去

class SecureCookieSessionInterface(SessionInterface):
   
    salt = "cookie-session"
   
    digest_method = staticmethod(hashlib.sha1)
  
    key_derivation = "hmac"
   
    serializer = session_json_serializer
    session_class = SecureCookieSession

    def get_signing_serializer(self, app):
        if not app.secret_key:
            return None
        signer_kwargs = dict(
            key_derivation=self.key_derivation, digest_method=self.digest_method
        )
        return URLSafeTimedSerializer(
            app.secret_key,
            salt=self.salt,
            serializer=self.serializer,
            signer_kwargs=signer_kwargs,
        )
    # 取session的时候执行的
    def open_session(self, app, request):
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        ##cookie键是SESSION_COOKIE_NAME"=session
        val = request.cookies.get(app.session_cookie_name)

        print("open_session.session_cookie_name,", app.session_cookie_name, )
        if not val:
            return self.session_class()
        max_age = total_seconds(app.permanent_session_lifetime)
        try:
            data = s.loads(val, max_age=max_age)
            print("self.session_class(data)", self.session_class(data) )
            return self.session_class(data)
        except BadSignature:
            return self.session_class()

    #存session的时候执行的
    def save_session(self, app, session, response):
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)

        # If the session is modified to be empty, remove the cookie.
        # If the session is empty, return without setting the cookie.
        if not session:
            if session.modified:
                response.delete_cookie(
                    app.session_cookie_name, domain=domain, path=path
                )

            return
        # Add a "Vary: Cookie" header if the session was accessed at all.
        if session.accessed:
            response.vary.add("Cookie")

        if not self.should_set_cookie(app, session):
            return
        httponly = self.get_cookie_httponly(app)
        secure = self.get_cookie_secure(app)
        samesite = self.get_cookie_samesite(app)
        expires = self.get_expiration_time(app, session)
        # 把session做了一个加密,把整个session的key--》val,全部加密,的到一个value值,
        #session是一个大字典,
        val = self.get_signing_serializer(app).dumps(dict(session))
        # 他把session加密后得到的val存到cookie里面了
        #cookie键是SESSION_COOKIE_NAME"=session
        print("源码中的session",dict(session))
        print("app.session_cookie_name,",app.session_cookie_name,)
        response.set_cookie(
            app.session_cookie_name,
            val,
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )

posted @ 2020-03-19 16:41  Jeff的技术栈  阅读(596)  评论(1编辑  收藏  举报
回顶部