flask_cookie_session
http的会话控制
所谓的会话,就是客户端浏览器和服务端网站之间一次完整的交互过程.
会话的生命周期:
- 会话的开始:是在用户通过浏览器第一次访问服务端网站开始.
- 会话的结束:时在用户通过关闭浏览器以后,与服务端断开.
所谓的会话控制:就是客户端浏览器和服务端网站之间,进行多次http请求响应的时候,服务端可以记录、跟踪和识别用户的信息而已。
会话的意义体现在哪里呢?
首先我们知道http 是一种无状态协议,协议对于交互性场景没有记忆能力。
无状态:指一次用户请求时,服务器无法知道之前这个用户做过什么,每次请求对于服务器端都是一次新的请求。
无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接。
但是,有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
实现状态保持主要有两种类型:
- 在客户端存储信息使用
Cookie - 在服务器端存储信息使用
Session
Cookie
Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义。
使用场景: 登录状态, 浏览历史, 网站足迹,购物车 [不登录也可以使用购物车]
相关注意事项:
-
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
-
Cookie基于域名安全,不同域名的Cookie是不能互相访问的
- 如访问baidu.com时向浏览器中写入了Cookie信息,使用同一浏览器访问sogou.com时,无法访问到baidu.com写的Cookie信息
-
当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息
设置cookie
设置cookie需要通过flask的Response响应对象来进行设置,由响应对象会提供了方法set_cookie给我们可以快速设置cookie信息。
@app.route("/set_cookie")
def set_cookie():
"""设置cookie"""
response = make_response("ok")
# response.set_cookie(key="变量名",value="变量值",max_age="有效时间/秒")
response.set_cookie("username","xiaoming",100)
"""如果cookie没有设置过期时间,则默认过期为会话结束过期"""
"""cookie在客户端中保存时,用一个站点下同变量名的cookie会覆盖"""
response.set_cookie("age","100")
return response
获取cookie
@app.route("/get_cookie")
def get_cookie():
"""获取cookie"""
print(request.cookies)
print(request.cookies.get("username"))
print(request.cookies.get("age"))
"""打印效果:
{'username': 'xiaoming'}
"""
return ""
删除cookie
@app.route("/del_cookie")
def del_cookie():
"""删除cookie"""
response = make_response("ok")
#把对应名称的cookie设置为过期时间,则可以达到删除cookie
response.set_cookie("username","",0)
return response
Session
session即安全的cookie,就是把cookie数据进行了加密处理。对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
session的作用
session在web程序中发挥着很大的作用,其中最重要的功能就是存储用户的认证信息。我们先来看看基于浏览器的用户认证是如何实现的。当我们使用浏览器登录某个社交网站时,会在登录表单中填写用户名和密码,单击登录按钮后,会向服务器发送一个包含认证数据的请求,服务器接收请求后会查找对应的用户名,然后验证密码是否匹配,如果匹配,就在响应报文中设置一个cookie,比如”login_user:bobo”,响应被浏览器接收后,cookie会被保存在浏览器中。当用户再次向这个服务器发送请求时,根据请求携带的cookie字段中的内容,服务器上的程序就可以判断用户的认证状态,并识别出用户。
使用session对象加密cookie数据
上述流程中是存在问题的,问题就是,在浏览器中添加或者修改cookie是很容易的事,仅通过浏览器插件就可以实现。所以,如果直接把认证信息以明文的方式存储在cookie中是非常不安全的,恶意用户可以通过伪造cookie的内容(login_user:bobo)来获得对网站的权限,冒充别人的账号。为了避免这个问题,需要对敏感的cookie内容进行加密。Flask通过了session对象来将cookie数据进行加密存储。
在Flask中,session对象用来加密Cookie。默认情况下,它会把数据存储在一个名为session的cookie里。
设置程序秘钥
session通过密钥对数据进行签名以加密数据,因此,我们得先设置一个密钥。这里的密钥就是一个具有复杂度和随机性的字符串。可以通过flask.secret_key属性或配置变量SECRET_KEY进行设置。
session的有效期默认是会话期,会话结束了,session就废弃了。
如果将来希望session的生命周期延长,可以session.permanent = True,默认为31天。
PERMANENT_SESSION_LIFETIME:session存活的时间周期,默认为31天
设置session
from flask import Flask, make_response, request,session
app = Flask(__name__)
class Config():
SECRET_KEY = "123456asdadad"
DEBUG = True
app.config.from_object(Config)
# 查看当前flask默认支持的所有配置项
# print(app.config)
"""
<Config {
'DEBUG': False,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31),
'USE_X_SENDFILE': False,
'LOGGER_NAME': '__main__',
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None,
'APPLICATION_ROOT': None,
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200),
'TRAP_BAD_REQUEST_ERRORS': False,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None
"""
@app.route("/set_session")
def set_session():
"""设置session"""
"""与cookie不同,session支持python基本数据类型作为值"""
session["username"] = "xiaohuihui"
session["info"] = {
"age":11,
"sex":True,
}
return "ok"
if __name__ == '__main__':
app.run(debug=True)
获取session
@app.route("/get_session")
def get_session():
"""获取session"""
print( session.get("username") )
print( session.get("info") )
return "ok"
删除session
@app.route("/del_session")
def del_session():
"""删除session"""
try:
del session["username"]
# session.clear() # 删除所有
except:
pass
return "ok"
- 思考:加密的session数据有没有可能被黑客窃取?
- SESSION_COOKIE_NAME = 'xxx':在浏览器的开发者工具中通过cookie找到的session的名称就变成了xxx。
- 如果黑客知道了你的secret_key和你的session的密文值后,就可以破解你的session,但是如果session的名称变了,则很难找到session的密文数据。
Session登录校验
- 基于session实现免密登录
# 基于session实现免密登录
from flask import Flask, session, request
from flask import render_template
app = Flask(import_name=__name__)
# app.secret_key = 'abc123'
class Config(object):
DEBUG = True
SECRET_KEY = 'abc123'
app.config.from_object(Config)
@app.route('/index')
def index():
if session.get('name'):
return 'ok'
return render_template('index.html')
@app.route('/login', methods=['POST', 'GET'])
def login():
name = request.form.get('username')
pwd = request.form.get('password')
radio = request.form.get('radio')
if name == 'gelong' and pwd == '123':
if radio:
session['name'] = 'gelong'
session['password'] = '123'
return 'ok'
else:
if session.get('name') and session.get('password'):
print(session.get('name')) # gelong
return '登录成功'
return 'error'
if __name__ == '__main__':
app.run()
- 将登录验证作用在多个视图函数中(普通写法)
@app.route('/aa')
def aa():
if session.get('name'):
return 'my is aa 页面'
return render_template('index.html')
@app.route('/bb')
def bb():
if session.get('name'):
return 'hello, i is bb'
return render_template('index.html')
#造成代码冗余
- 装饰器写法
# 使用装饰器写法为每个函数添加验证是否登录
def login_session(func):
def inner(*args, **kwargs):
if session.get('name'):
return func()
else:
return render_template('index.html')
return inner
@app.route('/aa')
@login_session
def aa():
return 'my is aa 页面'
@app.route('/bb')
@login_session
def bb():
return 'hello, i is bb'
#上述代码报错了:AssertionError: View function mapping is overwriting an existing endpoint function: inner表示视图函数名重复了!都叫inner
-
视图函数名称重复后的处理方式:
- 在同名视图函数的@app的装饰器中加入endpoint=’xxx‘
- endpoint是用来反向生成url地址的。endpoint就是给路由函数起一个别名
- endpoint默认名就是视图函数名
@app.route('/aa', endpoint='aa') # 给路由函数起个别名 @login_session def aa(): return 'my is aa 页面' -
假设现在需要将装饰器应用到100个视图函数中,则是否需要在100个视图函数中都应用endpoint呢?
- 使用functools,会获取函数原始的名称
# 使用functools, 会获取函数原始的名称 import functools def login_session(func): @functools.wraps(func) def inner(*args, **kwargs): if session.get('name'): return func() else: return render_template('index.html') return inner @app.route('/aa') # 给路由函数起个别名 @login_session def aa(): return 'my is aa 页面' @app.route('/bb') @login_session def bb(): return 'hello, i is bb'
本文来自博客园,作者:长情不羁的五年,转载请注明原文链接:https://www.cnblogs.com/grlend/articles/14395624.html

浙公网安备 33010602011771号