Flask-Login 使用和进阶
在使用flask时,构建一个系统,用户登录注册是一个必不可少的过程,通常是使用Flask-Login模块。下面介绍使用Flask-Login登录注销,以及帮助大家解答一些可能比较常见的问题。
使用入门
首先,先概述下例子,有三个url,分别是:
1
2
3
|
/
auth
/
login
用于登录
/
auth
/
logout
用于注销
/
test
用于测试,需要登录才能访问
|
安装必要的库
1
2
3
4
|
pip
install
Flask
==
0.10.1
pip
install
Flask
-
Login
==
0.3.2
pip
install
Flask
-
WTF
==
0.12
pip
install
WTForms
==
2.1
|
编写web框架
首先,在开始登录之前,我们先把整个 web 的框架搭建出来,也就是,我们要能够先在不登录的情况下访问到上面提到的三个url,这个架构比较简单了,我就直接放在一个叫做 app.py 的文件中了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#!/usr/bin/env python
# encoding: utf-8
from
flask
import
Flask
,
Blueprint
app
=
Flask
(
__name__
)
# url redirect
auth
=
Blueprint
(
'auth'
,
__name__
)
@
auth
.
route
(
'/login'
,
methods
=
[
'GET'
,
'POST'
]
)
def
login
(
)
:
return
"login page"
@
auth
.
route
(
'/logout'
,
methods
=
[
'GET'
,
'POST'
]
)
def
logout
(
)
:
return
"logout page"
# test method
@
app
.
route
(
'/test'
)
def
test
(
)
:
return
"yes , you are allowed"
app
.
register_blueprint
(
auth
,
url_prefix
=
'/auth'
)
app
.
run
(
debug
=
True
)
|
现在,我们可以尝试一下运行一下这个框架,使用 python app.py 运行即可,然后打开浏览器,分别访问一下,看一下是否都正常
1
2
3
|
http
:
//localhost:5000/test
http
:
//localhost:5000/auth/login
http
:
//localhost:5000/auth/logout
|
设置登录才能查看
现在框架已经设置完毕,那么我们就可以尝试一下设置登录需求的,也就是说我们将 test 和 auth/logout 这两个 page 设置成登录之后才能查看。因为这个功能已经和 login 有关系了,所以这时我们就需要使用到 Flask-Login了。我们可以这样来更改代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
#!/usr/bin/env python
# encoding: utf-8
from
flask
import
Flask
,
Blueprint
from
flask
.
ext
.
login
import
LoginManager
,
login_required
app
=
Flask
(
__name__
)
# 以下这段是新增加的============
app
.
secret_key
=
's3cr3t'
login_manager
=
LoginManager
(
)
login_manager
.
session_protection
=
'strong'
login_manager
.
login_view
=
'auth.login'
login_manager
.
init_app
(
app
)
@
login_manager
.
user_loader
def
load_user
(
user_id
)
:
return
None
# 以上这段是新增加的============
auth
=
Blueprint
(
'auth'
,
__name__
)
@
auth
.
route
(
'/login'
,
methods
=
[
'GET'
,
'POST'
]
)
def
login
(
)
:
return
"login page"
@
auth
.
route
(
'/logout'
,
methods
=
[
'GET'
,
'POST'
]
)
@
login_required
def
logout
(
)
:
return
"logout page"
# test method
@
app
.
route
(
'/test'
)
@
login_required
def
test
(
)
:
return
"yes , you are allowed"
app
.
register_blueprint
(
auth
,
url_prefix
=
'/auth'
)
app
.
run
(
debug
=
True
)
|
其实我们就增加了两项代码,一项是初始化 LoginManager 的, 另外一项就是给test 和 auth.logout添加了login_required 的装饰器,表示要登录了才能访问。
你也许会有疑问:
1
|
@
login_manager
.
user_loader
|
这个装饰器是干嘛用的。这个在后面的 Question 中有详细得介绍,在这里我们只需要知道这个函数需要返回指定 id 的用户,如果没有就返回 None。这里因为设置框架所以就默认返回 None。
用户授权
到此,我们发现访问 test 是不能访问的,会被重定向到 login 的那个 page。那我们看一下我们现在的代码,我们发现 login_required 有了, 那么就差login了,好,接下来就写login,我们来看看Flask-Login的文档,会发现一个叫做login_user的函数,看看它的原型:
1
|
flask
.
ext
.
login
.
login_user
(
user
,
remember
=
False
,
force
=
False
,
fresh
=
True
)
|
这里需要一个user的对象,所以我们就先创建一个Model,其实,这个Model还是有一点讲究的,所以我们最好是继承自Flask-Login的UserMixin,然后需要实现几个方法,Model 为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# user models
class
User
(
UserMixin
)
:
def
is_authenticated
(
self
)
:
return
True
def
is_actice
(
self
)
:
return
True
def
is_anonymous
(
self
)
:
return
False
def
get_id
(
self
)
:
return
"1"
|
这里给所有的函数都返回了默认值,默认对应的情况是这个用户已经登录,并且是有效的。
然后在 login 的 view 里面 login_user, logout的view里面logout_user,这样整个登录过程就连接起来了,最后的代码是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
#!/usr/bin/env python
# encoding: utf-8
from
flask
import
Flask
,
Blueprint
from
flask
.
ext
.
login
import
(
LoginManager
,
login_required
,
login_user
,
logout_user
,
UserMixin
)
app
=
Flask
(
__name__
)
# user models
class
User
(
UserMixin
)
:
def
is_authenticated
(
self
)
:
return
True
def
is_actice
(
self
)
:
return
True
def
is_anonymous
(
self
)
:
return
False
def
get_id
(
self
)
:
return
"1"
# flask-login
app
.
secret_key
=
's3cr3t'
login_manager
=
LoginManager
(
)
login_manager
.
session_protection
=
'strong'
login_manager
.
login_view
=
'auth.login'
login_manager
.
init_app
(
app
)
@
login_manager
.
user_loader
def
load_user
(
user_id
)
:
user
=
User
(
)
return
user
auth
=
Blueprint
(
'auth'
,
__name__
)
@
auth
.
route
(
'/login'
,
methods
=
[
'GET'
,
'POST'
]
)
def
login
(
)
:
user
=
User
(
)
login_user
(
user
)
return
"login page"
@
auth
.
route
(
'/logout'
,
methods
=
[
'GET'
,
'POST'
]
)
@
login_required
def
logout
(
)
:
logout_user
(
)
return
"logout page"
# test method
@
app
.
route
(
'/test'
)
@
login_required
def
test
(
)
:
return
"yes , you are allowed"
app
.
register_blueprint
(
auth
,
url_prefix
=
'/auth'
)
app
.
run
(
debug
=
True
)
|
总结
到此,这就是一个比较精简的Flask-Login 教程了,通过这个框架大家可以自行扩展,达到更丰富的功能,后续会连续这个Login 功能继续讲解一下权限控制。
问题
未登录访问鉴权页面如何处理:
如果未登录访问了一个做了login_required限制的view,那么flask-login会默认flash一条消息,并且将重定向到log in view, 如果你没有指定log in view, 那么 flask-login将会抛出一个401错误。
如何指定log in view:
指定log in view 只需要直接设置login_manager即可:
1
|
login_manager
.
login_view
=
"auth.login"
|
如何自定义flash消息:
如果需要自定义 flash 的消息,那么还是简单设置 login_manager,
1
2
|
login_manager
.
login_message
=
u
"请登录!"
|
还可以设置 flash 消息的级别,一般设置成 info 或者 error:
1
|
login_manager
.
login_message_category
=
"info"
|
自定义未登录处理函数:
如果你不想使用默认的规则,那么你也可以自定义未登录情况的处理函数,只需要使用 login_manager 的 unauthorized_handler 装饰器即可。
1
2
3
4
|
@
login_manager
.
unauthorized_handler
def
unauthorized
(
)
:
# do stuff
return
render_template
(
"some template"
)
|
匿名用户是怎么处理的?有哪些属性?
在 flask-login 中,如果一个匿名用户访问站点,那么 current_user 对象会被设置成一个 AnonymousUserMixin 的对象,AnonymousUserMixin 对象有以下方法和属性:
- is_active and is_authenticated are False
- is_anonymous is True
- get_id() returns None
自定义匿名用户Model:
如果你有需求自定义匿名用户的 Model,那么你可以通过设置 login_manager 的 anonymous_user 属性来实现,而赋值的对象只需是可调用对象(class 和 function都行)即可。
1
2
|
login_manager
.
anonymous_user
=
MyAnonymousUser
|
Flask-Login如何加载用户的:
当一个请求过来的时候,如果 ctx.user 没有值,那么 flask-login 就会使用 session 中 session['user_id'] 作为参数,调用 login_manager 中使用 user_loader 装饰器设置的 callback 函数加载用户,需要注意的是,如果指定的 user_id 无效,不应该抛出异常,而是应该返回 None。
1
2
3
4
|
@
login_manager
.
user_loader
def
load_user
(
user_id
)
:
return
User
.
get
(
user_id
)
|
session['user_id'] 其实是在调用 login_in 函数之后自动设置的。
如何控制Flask-Login的session过期时间:
在 Flask-Login 中,如果你不特殊处理的话,session 是在你关闭浏览器之后就失效的。也就是说每次重新打开页面都是需要重新登录的。
如果你需要自己控制 session 的过期时间的话,
- 首先需要设置 login_manager 的 session类型为永久的,
- 然后再设置 session 的过期时间
1
2
|
session
.
permanent
=
True
app
.
permanent_session_lifetime
=
timedelta
(
minutes
=
5
)
|
同时,还需要注意的是 cookie 的默认有效期其实是 一年 的,所以,我们最好也设置一下:
1
|
login_manager
.
remember_cookie_duration
=
timedelta
(
days
=
1
)
|
如何在同域名下的多个系统共享登录状态
这个需求可能在公司里面会比较常见,也就是说我们一个公司域名下面会有好多个子系统,但是这些子系统都是不同部门开发的,那么,我们如何在这不同系统间共享登录状态?也就是说,只要在某一个系统登录了,在使用其他系统的时候也共享着登录的状态,不需要再次登录,除非登录失效。
这个问题因为写这篇文章已经花了3个多小时,如果要继续对这个文章进行更深的探讨的话,可能需要另外开一篇文章,这里给个思路,暂时先挖一个坑,大家有兴趣可以参照
Server-side Sessions with Redis
这个说明尝试,也差不多是类似的解决方法。
成长的对话版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!