1、使用Session来保存用户信息
在上一节教程中,我们使用Flask搭建博客网站后,首先要进入127.0.0.1:5000/signin页面注册一个用户名,然后进入127.0.0.1:5000/login登录页面输入用户名和密码,当用户名和密码验证通过后,用户在博客网站中的状态就是登录状态了。这时候,用户浏览博客网站各个页面时,都可以保持登录状态,即使在页面刷新后,仍然可以保持登录状态,直到关闭浏览器后才会退出登录状态。这个过程,是通过Python的Session (会话)功能来实现的。
(1)Session (会话)的概念
Session在网络应用中被称为“会话控制”,当我们使用浏览器访问网站服务器时,服务器为了保存用户状态而创建的一个特殊的对象。简而言之,Session就是一个对象,用于存储信息。Session可以在浏览器端和服务器端之间建立的一种持久化的连接,用于存储用户信息和状态,使得用户在多个页面间可以保持一定的状态。
Session是一种在服务器端保存的用户会话信息,而不是在浏览器端保存的。当用户通过浏览器第一次登录某一个网站时,网站服务器会为该用户创建一个唯一的会话ID,并将用户的会话信息以某种形式保存在网站服务器上,形成Session。这样,当用户浏览器再次访问该网站时,网站服务器会通过Session保存的会话ID找到对应的会话信息,从而实现用户状态的保持。
比如今天是双十一,用户登录了某购物网站,并且浏览了大量商品,用户在此会话期间均可以保持登录状态,购物车里放了多少件物品,这些记录都会被保存在Session中。
Session的主要优势在于其数据安全性较高,因为数据存储在服务器端,用户无法直接修改或者伪造Session中的数据。同时,Session机制也提供了更加灵活的数据存储方式,能够保存复杂的数据结构,这对于需要保存用户状态信息的应用来说是非常有用的。
(2)Session在Python中的实现
在Python中,Session的实现通常是基于Web框架的支持,比如Flask、Django等框架。这些框架提供了相应的Session管理机制,开发者可以通过简单的配置就可以使用Session。
在Flask框架中,Session的使用非常简单,只需要通过flask.session对象来进行存储和读取即可。
在上一节教程中使用Flask搭建的博客网站,在app.py中主要是通过Flask-Login模块中的login_user()方法实现用户的登录过程,logout_user()方法实现登出功能,current_user属性获取当前登录的用户。login_user()方法实现登录过程中,主要是通过flask.session对象来进行存储用户信息。
我们打开Flask-Login模块的安装目录Pyhint\condition\Python38\Lib\site-packages\flask_login,用编辑器打开目录下的utils.py文件,可以看到login_user()方法的代码如下:
from flask import session
def login_user(user, remember=False, duration=None, force=False, fresh=True):
if not force and not user.is_active:
return False
user_id = getattr(user, current_app.login_manager.id_attribute)()
session["_user_id"] = user_id
session["_fresh"] = fresh
session["_id"] = current_app.login_manager._session_identifier_generator()
if remember:
session["_remember"] = "set"
if duration is not None:
try:
# equal to timedelta.total_seconds() but works with Python 2.6
session["_remember_seconds"] = (
duration.microseconds
+ (duration.seconds + duration.days * 24 * 3600) * 10**6
) / 10.0**6
except AttributeError as e:
raise Exception(
f"duration must be a datetime.timedelta, instead got: {duration}"
) from e
current_app.login_manager._update_request_context_with_user(user)
user_logged_in.send(current_app._get_current_object(), user=_get_user())
return True
从上面的代码中,可以看出login_user()方法是通过“session['user_id'] = user_id”来将用户的ID存储进Session当中,后面紧跟着将fresh信息、session id信息、remember信息分别存储进Session中。这些Session数据都会被保存在网站服务器上,浏览器端每次请求网站服务器的时候都会发送当前会话session id,网站服务器会根据当前session id判断相应的用户数据标志,以确定用户是否登录或具有某种权限。由于数据是存储在网站服务器上面,所以用户不能伪造。
这里需要注意的是,使用Session前,在app.py中必须要通过“app.config['SECRET_KEY']”设置SECRET_KEY进行加密,以确保安全性,否则程序会报错的。
2、Cookie的使用
在Web网站开发中,我们常常需要存储用户的信息,例如用户的登录状态或者个性化设置。除了前面介绍的Session方式,Flask框架还提供了Cookie方式来完成这个任务。
(1)Cookie的概念
Cookie是一种由网站服务器保存在用户浏览器端的一小块数据,用于记录用户的一些状态信息。当用户访问一个网站时,网站服务器会向浏览器发送一个包含Cookie信息的响应头,浏览器接收到这个响应头后,会将Cookie信息保存在本地。当用户再次访问该网站时,浏览器会自动将保存的Cookie信息发送给服务器,服务器通过解析这些信息来识别用户。
网站服务器向浏览器发送包含Cookie信息的响应头时,可以通过在HTTP响应头中包含Set-Cookie字段来设置Cookie。以下是一个简单示例:
HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Strict
Content-Type: text/html
<html>
...
</html>
Set-Cookie: 头部字段是由网站服务器在HTTP响应中发送给浏览器端的,用于在浏览器端存储一条新的Cookie。它的一般格式如下:
Set-Cookie: `name=value` [; expires=`date`] [; domain=`domain`] [; path=`path`] [; secure] [; httponly] [; samesite=`strict`/`lax`/`none`]
其中,各个参数的解析如下:
name=value: 表示要设置的Cookie的名称和值。
expires=date: 指定Cookie的过期时间,如果不设置,Cookie默认在浏览器关闭时过期。
domain=domain: 指定Cookie的有效域,控制哪些域可以访问该Cookie。
path=path: 指定Cookie的有效路径,控制哪些路径下的页面可以访问该Cookie。
secure: 如果设置了该选项,Cookie只能通过HTTPS协议传输。
httponly: 如果设置了该选项,Cookie将无法通过JavaScript脚本访问,有助于防止跨站脚本攻击(XSS)。
samesite=strict/lax/none: 该选项用于控制跨站请求伪造(CSRF)攻击。strict表示仅在同站点请求时发送Cookie,lax表示在导航到其他站点时不发送Cookie,仅在顶级导航时发送;none表示总是发送Cookie。
(2)Cookie与Session的区别
Cookie是将用户数据通过加密的方式保存在浏览器上,安全性低,存储量有限。而Session则是将用户数据保存在网站服务器上,安全性高,Session一般存储在数据库,存储量较大。
如果浏览器端使用了Cookie保存用户数据,那么所有的数据都会保存在浏览器端,比如我们登录网站以后,网站服务器设置了Cookie用户名,那么当我们再次请求网站服务器的时候,浏览器会将Cookie保存的用户名一块发送给网站服务器,这些变量有一定的特殊标记。网站服务器会解释为Cookie变量,所以只要不关闭浏览器,那么Cookie变量一直是有效的,所以能够保证长时间登录不掉线。
Cookie不是很安全,由于Cookie存储在浏览器端,因此容易受到XSS攻击和CSRF攻击。别人可以分析存放在本地的Cookie并进行Cookie欺骗,甚至通过伪造的Cookie进行登录。如果主要考虑到安全应当使用Session,并且单个Cookie存放在浏览器端的限制是3K,就是说一个站点在浏览器端存放的Cookie不能3K。所以建议将登录信息等重要信息存放为Session中,其他信息如果需要保留,可以放在Cookie中。
下面我们创建一个简单的Flask应用,并在Flask中设置和读取Cookie。例如:
from flask import Flask, request, make_response
app = Flask(__name__)
@app.route("/set")
def setcookie():
resp = make_response("已成功设置Cookie")
resp.set_cookie("username", "张三")
return resp
@app.route("/get")
def getcookie():
username = request.cookies.get("username")
return "你的用户名是:" + username
if __name__ == "__main__":
app.run()
上面的例子中,我们通过创建make_response对象,并使用set_cookie()方法设置了一个名为“username”、值为“张三”的Cookie。该Flask应用包含两个路由:“/set”和“/get”。当我们通过浏览器访问127.0.0.1:5000/set后,浏览器就会成功设置一个名为“username”的Cookie,并且浏览器返回“已成功设置Cookie”的信息。接着,我们访问127.0.0.1:5000/get时,服务器会读取保存在浏览器端的Cookie数据,并返回“你的用户名是:张三”信息,即使在页面多次刷新后,仍然可以提示该信息,直到退出浏览器。
在使用Session和Cookie时,应根据具体的应用场景来选择合适的技术。一般来说,如果需要存储大量的数据或者需要保证数据的安全性,应使用Session技术;如果需要存储少量的数据或者需要在客户浏览器端之间共享数据,应使用Cookie技术。
另外,需要注意的是,Session和Cookie都是有安全风险的。如果Session或Cookie被恶意攻击者截取,就会导致用户的数据泄露。因此,在使用Session和Cookie时,应根据具体的应用场景来选择合适的安全性措施,例如使用HTTPS协议传输数据、设置Cookie的HttpOnly属性等。