19.设置服务器端Session【番外】

11.保存登录状态与注销功能这篇文章中,我们使用了session来保存username,实际上Flask默认的session功能,是客户端session(client-side session),与之相对的是服务器端session(server-side session)。简单来说,这里的客户端session是将username加密后,以cookie的形式返还给客户端,客户端后续访问网站就携带着这个cookie,服务器解密cookie得到username。也就是说,如果知道了加密方法和cookie内容,就可以解密出username,这样是不够安全的。
今天我们来实现服务器端session(server-side session),原理很简单,实际上在【python socket编程】—— 5.实现cookie和session这篇文章中我们已经做过了。现在我们用数据库来保存session,并为其设置有效期。整个逻辑是这样的:用户登录后,生成一个随机字符串,将其作为session id,与对应的username和过期时间一起存入数据库,然后将session id作为cookie返回给客户端,客户端后续访问时,携带着含有session idcookie,服务器通过cookie中的session id在数据库中检索session数据,判断登录状态。

建立一个sessions表(ORM模型)来存储session,字段如下:

class MySession(db.Model):
    __tablename__ = 'sessions'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    # s_id代表session id,也是后面返回给客户端的cookie
    s_id = db.Column(db.String(24), nullable=False)
    username = db.Column(db.String(64), nullable=False)
    start_time = db.Column(db.DateTime, nullable=False)
    expire_time = db.Column(db.DateTime, nullable=False)

视图函数代码如下:

@app.route('/session/', methods=['GET', 'POST'])
def test_session():
    username = None
    if request.method == 'GET':
        s_id = request.cookies.get('sid')
        if s_id:
            mysession = MySession.query.filter(MySession.s_id == s_id).first()
            if mysession and mysession.expire_time > datetime.now():
                    username = mysession.username
        return render_template('session.html', username=username)
    else:
        username = request.form.get('username')
        s_id = random_strings(24)
        now = datetime.now()
        expire_time = now + timedelta(seconds=10)
        mysession = MySession(s_id=s_id, username=username, start_time=now, expire_time=expire_time)
        db.session.add(mysession)
        db.session.commit()
        response = make_response(redirect(url_for('test_session')))
        response.set_cookie('sid', s_id)
        return response

我们从POST方法讲起,当用户POST一个username过来时(为了简单,session.html只有用户名没有密码),生成一个随机字符串(random_strings是自己编写的一个小函数)作为session id,然后获取现在的时间now和过期时间expire_time(为了演示方便,过期时间是10秒之后),然后将这些信息存入MySession模型中,最后使用make_response方法生成一个response对象(这个对象有set_cookie方法,这也是Flask设置cookie的常规方法),并为其设置cookieset_cookie第一个参数'sid'key,第二个参数是value(session id),之后返回response对象。当请求是GET时候,首先就会使用request.cookies.get('sid')去获取cookie中的session id,如果获取到并且还在过期时间内,则向html传入username表明当前已经登录的用户。

最后html的内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    {% if username %}
    <p>Welcome {{ username }}</p>
    <button>Logout</button>
    {% else %}
    <form action="" method="post">
    <p>Username: <input type="text" name="username"></p>
    <button>Login</button>
    </form>
    {% endif %}
</div>
</body>
</html>

效果展示:
未登录时:

《19.设置服务器端Session【番外】》

登录后:

《19.设置服务器端Session【番外】》

此时数据库中的session信息:

《19.设置服务器端Session【番外】》

浏览器中的cookie内容:

《19.设置服务器端Session【番外】》

过期之后浏览器仍然携带这个cookie,但刷新网页又变成未登录的状态了。

    原文作者:Harpsichord1207
    原文地址: https://segmentfault.com/a/1190000013246129
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞