Flask扩展系列(八)–用户会话管理

安装和启用

遵循标准的Flask扩展安装和启用方式,先通过pip来安装扩展:

$ pip install Flask-Login

接下来创建扩展对象实例:

1

2

3

4

5

from flask import Flask

from flask.ext.login import LoginManager

 

app = Flask(__name__)

login_manager = LoginManager(app)

 

同时,你可以对LoginManager对象赋上配置参数:

1

2

3

4

5

6

7

8

9

# 设置登录视图的名称,如果一个未登录用户请求一个只有登录用户才能访问的视图,

# 则闪现一条错误消息,并重定向到这里设置的登录视图。

# 如果未设置登录视图,则直接返回401错误。

login_manager.login_view = 'login'

# 设置当未登录用户请求一个只有登录用户才能访问的视图时,闪现的错误消息的内容,

# 默认的错误消息是:Please log in to access this page.。

login_manager.login_message = 'Unauthorized User'

# 设置闪现的错误消息的类别

login_manager.login_message_category = "info"

 

编写用户类

使用Flask-Login之前,你需要先定义用户类,该类必须实现以下三个属性和一个方法:

当用户登录成功后,该属性为True。

如果该用户账号已被激活,且该用户已登录成功,则此属性为True。

是否为匿名用户(未登录用户)。

每个用户都必须有一个唯一的标识符作为ID,该方法可以返回当前用户的ID,这里ID必须是Unicode。

  1. 属性 is_authenticated
  2. 属性 is_active
  3. 属性 is_anonymous
  4. 方法 get_id()

因为每次写个用户类很麻烦,Flask-Login提供了”UserMixin”类,你可以直接继承它即可:

1

2

3

4

from flask.ext.login import UserMixin

 

class User(UserMixin):

    pass

 

从会话或请求中加载用户

在编写登录登出视图前,我们要先写一个加载用户对象的方法。它的功能是根据传入的用户ID,构造一个新的用户类的对象。为了简化范例,我们不引入数据库,而是在列表里定义用户记录。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# 用户记录表

users = [

    {'username': 'Tom', 'password': '111111'},

    {'username': 'Michael', 'password': '123456'}

]

 

# 通过用户名,获取用户记录,如果不存在,则返回None

def query_user(username):

    for user in users:

        if user['username'] == username:

            return user

 

# 如果用户名存在则构建一个新的用户类对象,并使用用户名作为ID

# 如果不存在,必须返回None

@login_manager.user_loader

def load_user(username):

    if query_user(username) is not None:

        curr_user = User()

        curr_user.id = username

        return curr_user

上述代码中,通过”@login_manager.user_loader”装饰器修饰的方法,既是我们要实现的加载用户对象方法。它是一个回调函数,在每次请求过来后,Flask-Login都会从Session中寻找”user_id”的值,如果找到的话,就会用这个”user_id”值来调用此回调函数,并构建一个用户类对象。因此,没有这个回调的话,Flask-Login将无法工作。

有一个问题,启用Session的话一定需要客户端允许Cookie,因为Session ID是保存在Cookie中的,如果Cookie被禁用了怎么办?那我们的应用只好通过请求参数将用户信息带过来,一般情况下会使用一个动态的Token来表示登录用户的信息。此时,我们就不能依靠”@login_manager.user_loader”回调,而是使用”@login_manager.request_loader”回调。

1

2

3

4

5

6

7

8

9

10

11

from flask import request

 

# 从请求参数中获取Token,如果Token所对应的用户存在则构建一个新的用户类对象

# 并使用用户名作为ID,如果不存在,必须返回None

@login_manager.request_loader

def load_user_from_request(request):

    username = request.args.get('token')

    if query_user(username) is not None:

        curr_user = User()

        curr_user.id = username

        return curr_user

为了简化代码,上面的例子就直接使用用户名作为Token了,实际项目中,大家还是要用一个复杂的算法来验证Token。

登录及登出

一切准备就绪,我们开始实现登录视图:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

from flask import render_template, redirect, url_for, flash

from flask.ext.login import login_user

 

@app.route('/login', methods=['GET', 'POST'])

def login():

    if request.method == 'POST':

        username = request.form.get('username')

        user = query_user(username)

        # 验证表单中提交的用户名和密码

        if user is not None and request.form['password'] == user['password']:

            curr_user = User()

            curr_user.id = username

 

            # 通过Flask-Login的login_user方法登录用户

            login_user(curr_user)

 

            # 如果请求中有next参数,则重定向到其指定的地址,

            # 没有next参数,则重定向到"index"视图

            next = request.args.get('next')

            return redirect(next or url_for('index'))

 

        flash('Wrong username or password!')

    # GET 请求

    return render_template('login.html')

上述代码同之前Login视图最大的不同就是你在用户验证通过后,需要调用Flask-Login扩展提供的”login_user()”方法来让用户登录,该方法需传入用户类对象。这个”login_user()”方法会帮助你操作用户Session,并且会在请求上下文中记录用户信息。另外,在具体实现时,建议大家对”next”参数值作验证,避免被URL注入攻击。

“login.html”模板很简单,就是显示一个用户名密码的表单:

1

2

3

4

5

6

7

8

9

10

11

<!doctype html>

<title>Login Sample</title>

<h1>Login</h1>

{% with messages = get_flashed_messages() %}

    <div>{{ messages[0] }}</div>

{% endwith %}

<form action="{{ url_for('login') }}" method="POST">

    <input type="text" name="username" id="username" placeholder="Username"></input>

    <input type="password" name="password" id="password" placeholder="Password"></input>

    <input type="submit" name="submit"></input>

</form>

 

接下来,让我们写个index视图:

1

2

3

4

5

6

from flask.ext.login import current_user, login_required

 

@app.route('/')

@login_required

def index():

    return 'Logged in as: %s' % current_user.get_id()

装饰器”@login_required”就如同我们在进阶系列第四篇中写的一样,确保只有登录用户才能访问这个index视图,Flask-Login帮我们实现了这个装饰器。如果用户未登录,它就会将页面重定向到登录视图,也就是我们在第一节中配置的”login_manager.login_view”的视图。

同时,重定向的地址会自动加上”next”参数,参数的值是当前用户请求的地址,这样,登录成功后就会跳转回当前视图。可以看到我们对于用户登录所需要的操作,这个装饰器基本都实现了,很方便吧!

Flask-Login还提供了”current_user”代理,可以访问到登录用户的用户类对象。我们在模板中也可以使用这个代理。让我们再写一个home视图:

1

2

3

4

@app.route('/home')

@login_required

def home():

    return render_template('hello.html')

模板代码如下:

1

2

3

4

5

<!doctype html>

<title>Login Sample</title>

{% if current_user.is_authenticated %}

  <h1>Hello {{ current_user.get_id() }}!</h1>

{% endif %}

在上面的模板代码中,我们直接访问了”current_user”对象的属性和方法。

登出视图也很简单,Flask-Login提供了”logout_user()”方法来帮助你清理用户Session。

1

2

3

4

5

6

7

from flask.ext.login import logout_user

 

@app.route('/logout')

@login_required

def logout():

    logout_user()

    return 'Logged out successfully!'

 

自定义未授权访问的处理方法

“@login_required”装饰器对于未登录用户访问的默认处理是重定向到登录视图,如果我们不想它这么做的话,可以自定义处理方法:

1

2

3

@login_manager.unauthorized_handler

def unauthorized_handler():

    return 'Unauthorized'

这个”@login_manager.unauthorized_handler”装饰器所修饰的方法就会代替”@login_required”装饰器的默认处理方法。有了上面的代码,当未登录用户访问index视图时,页面就会直接返回”Unauthorized”信息。

Remember Me

在登录视图中,调用”login_user()”方法时,传入”remember=True”参数,即可实现“记住我”功能:

1

2

3

...

            login_user(curr_user, remember=True)

...

Flask-Login是通过在Cookie实现的,它会在Cookie中添加一个”remember_token”字段来记住之前登录的用户信息,所以禁用Cookie的话,该功能将无法工作。

Fresh登录

当用户通过账号和密码登录后,Flask-Login会将其标识为Fresh登录,即在Session中设置”_fresh”字段为True。而用户通过Remember Me自动登录的话,则不标识为Fresh登录。对于”@login_required”装饰器修饰的视图,是否Fresh登录都可以访问,但是有些情况下,我们会强制要求用户登录一次,比如修改登录密码,这时候,我们可以用”@fresh_login_required”装饰器来修饰该视图。这样,通过Remember Me自动登录的用户,将无法访问该视图:

1

2

3

4

5

6

from flask.ext.login import fresh_login_required

 

@app.route('/home')

@fresh_login_required

def home():

    return 'Logged in as: %s' % current_user.get_id()

 

会话保护

Flask-Login自动启用会话保护功能。对于每个请求,它会验证用户标识,这个标识是由客户端IP地址和User Agent的值经SHA512编码而来。在用户登录成功时,Flask-Login就会将这个值保存起来以便后续检查。默认的会话保护模式是”basic”,为了加强安全性,你可以启用强会话保护模式,方法是配置LoginManager实例对象中的”session_protection”属性:

1

login_manager.session_protection = "strong"

在”strong”模式下,一旦用户标识检查失败,便会清空所用Session内容,并且Remember Me也失效。而”basic”模式下,只是将登录标为非Fresh登录。你还可以将”login_manager.session_protection”置为None来取消会话保护。

更多参考资料

Flask-Login的官方文档
Flask-Login的源码

本篇的示例代码可以在这里下载。

格式日志发布于2016年4月29日作者Billy.J.Hee分类Python、编程标签Flask、Login、Session

文章导航

上一上篇文章:Flask扩展系列(七)–表单

下一下篇文章:Flask扩展系列(九)–HTTP认证

《Flask扩展系列(八)–用户会话管理》有3个想法

  1. 张莹说道:

    2017年5月7日 下午9:42

    利用Flask-Login和session进行用户登录管理具体区别是什么呢?

    如何利用session记录其他需要保留的信息,例如上次访问页面的时间?

    多谢赐教!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

onmousemove和onmouseout事件的调用,和js使用双引号、单引号的时候应该注意的问题...

使用js的时候&#xff0c;统一使用双引号&#xff0c;然后通过反斜杠进行转义 ①如果同时使用单引号、和双引号的情况下容易出现问题&#xff0c;导致标签中表示的事件不能调用&#xff0c; ②导致由于标签没有封口而出现样式布局错误 1 <!DOCTYPE html>2 <html>3 …

C++ 学习书目

C书单 第一篇 一些同学问我&#xff0c;如何学好C&#xff0c;我没有别的办法给你们&#xff0c;唯一的办法就是读书&#xff0c;读大量的书&#xff0c;就可以解决。要把C作为日常语言&#xff0c;而不是一种程序语言&#xff0c;这样就好办了。 有人又要问我&#xff0c;那么…

CentOS6.5安装配置

一、网络设置&#xff1a; 1、命令&#xff1a;vim /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICEeth0 HWADDR00:0C:29:34:11:33 TYPEEthernet UUID6a0e083b-7d65-4afe-9d6f-f42f97659c89 ONBOOTyes NM_CONTROLLEDyes …

js踩过的一些坑

参考我的博客&#xff1a;http://www.isedwardtang.com/2017/08/29/js-bug/转载于:https://www.cnblogs.com/EdwardTang/p/7476769.html

开发中的几款小工具

文本编辑器 ckediter,kindediter,uediter比较多。 http://q.sohu.com/asset/group/ueditor/editor_all.js 马克鳗 用于: 截图测量&#xff0c;取颜色 代码比较工具 Beyond Compare sql书写智能提示工具 SQLPrompt sql自动提示,安装SQLPrompt工具options--->qualification---…

使用PDO总结

PHP使用PDO总结1、php.ini中开启PDO扩展&#xff1a; extensionphp_pdo.dll 重启Apache&#xff01; 2、PDO 构造方法 一共需要三个字段,分别为数据库配置信息&#xff0c;用户名&#xff0c;用户密码 其中数据库配置信息写法mysql:host192.16;post3306;charsetutf-8;dbnametes…

自己写的Python数据库连接类和sql语句拼接方法

python # SQL 查询语句sql "SELECT * FROM user where username %s" % username " and password %s" % password "" 参考&#xff1a; https://www.cnblogs.com/Xjng/p/3821827.html

注册表-显示回收站

WinXP系统下恢复不小心删掉的回收站图标&#xff01; 修改注册表法 1.单击“开始”\“运行”&#xff0c;在“打开”中键入“regedit”&#xff0c;运行注册表编辑器&#xff1b; 2.依次展开注册表至&#xff1a;HKEY&#xff3f;CURRENT&#xff3f;USER\Software\Microsoft\W…

自己如何获取ADO连接字符串

自己如何获取ADO连接字符串 摘自&#xff1a;http://blog.csdn.net/zyq5945/article/details/5586423 有时候我们参考网上的ADO连接字符串写未必就能连接上数据库。今天详细介绍下这个很流行的如何获取ADO字符串的方法&#xff0c;就能很容易直观看到这个连接字符串是否真能连接…

phpstorm+xdebug配置分享

一、选择XDEBUG扩展 xdebug下载地址&#xff1a;https://xdebug.org/download.php 注意&#xff1a;带"ts"是线程安全的意思&#xff0c;"nts"的他没有标示&#xff0c;也就是说&#xff0c;如果是nts的要下载没标示的&#xff0c;下载下来的文件名其实是有…

Flask框架Flask-Login用法分析

参考&#xff1a; https://www.cnblogs.com/cjnmy36723/p/5212047.html https://www.jianshu.com/p/06bd93e21945 Flask-Login插件中带了6种信号&#xff0c;可以基于其中的信号做一些额外工作&#xff0c;比如user_logged_in来记录用户的登录次数和登录IP等。 安装 ? 1 p…

spi驱动 (2):应用与测试

大幅度转载于:https://www.cnblogs.com/zhangyin-ethan/p/7481725.html

Mac安装PostgreSQL和测试安装结果

为什么80%的码农都做不了架构师&#xff1f;>>> 安装&#xff1a;brew install postgresql -v 这一步会安装它和它的各种依赖包&#xff0c;并且初始化元数据库内容添加到开机启动&#xff1a;ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents/ …

不可深交者

1&#xff1a;太过自私&#xff0c;不为他人考虑者&#xff0c;不可深交2&#xff1a;不讲诚信&#xff0c;多次爽约者&#xff0c;不可深交3&#xff1a;己过不该&#xff0c;屡劝屡犯者&#xff0c;不可深交4&#xff1a;不知感恩&#xff0c;过河拆桥者&#xff0c;不可深交…

MySQL--安装linux(5.6版本)

1 版本 目前MySQL数据库按用户群分为社区版(Community Server)和企业版(Enterprise/commercial)。--commercial授权版本 社区版是免费下载的&#xff0c;企业版需要付费且不能在线下载。 社区版分为3种&#xff1a; GA(General Availability)&#xff1a;官方推荐使用的版本&am…

linux命令行总结

简单命令 语法&#xff1a;#ls [路径] 表示列出指定路径下的文件夹和文件的名字&#xff0c;如果路径没有指定则列出当前路径下的语法&#xff1a;#ls -l [路径] 表示以列表的形式列出指定路径下的文件夹和文件的名字语法&#xff1a;#ls -la [路径] …

Flask-Session

https://pythonhosted.org/Flask-Session/

Andoid开发中生成二维码

2019独角兽企业重金招聘Python工程师标准>>> 第一步&#xff1a; 确定我们二维码的位置&#xff0c;即是在我们应用的哪个页面的哪个位置&#xff0c;简单讲就是用一个ImageView把二维码展示出来&#xff0c;我们就把二维码展示在下面布局activity_main.xml中的Imag…

Android中的onActivityResult和setResult方法的使用

$*********************************************************************************************$博主推荐&#xff1a;风萧兮兮易水寒&#xff0c;“天真”一去兮不复还。如何找到天真的那份快乐。小编倾力推荐app: 天真无谐下载方式&#xff1a;豌豆荚&#xff0c;应用宝…

单文件快速体验使用react输出hello_world

看了下react官方的hello world教程, 感觉对新手很不友好.codepen虽然好用, 但是封装太多东西, 看起来 太抽象. 还是喜欢像学习jQuery那样, 直接在单文件中引入必要的js文件, 然后直接运行的那种感觉. 如果使用VS Code, 建议安装Sublime Babel, 来提供对react语法的代码高亮. 基…