带有烧瓶安全扩展的基于令牌的身份验证

Posted

技术标签:

【中文标题】带有烧瓶安全扩展的基于令牌的身份验证【英文标题】:Token based authentication with flask-security extension 【发布时间】:2015-02-06 01:01:21 【问题描述】:

我目前正在寻找一种使用基于令牌的身份验证来保护 REST API 的方法。我正在使用 Flask 在 Python 中开发 API,并发现了 flask-security 扩展,它似乎有很多有趣的特性。

文档中提到的功能之一是令牌身份验证。

根据文档:

通过检索用户身份验证启用基于令牌的身份验证 通过使用身份验证详细信息执行 HTTP POST 来获取令牌 针对身份验证端点的 JSON 数据。成功调用 此端点将返回用户的 ID 和他们的身份验证 令牌。此令牌可用于随后的受保护请求中 资源。

但是,我仍然对如何使用烧瓶安全性实现此功能感到有些困惑。 一些在线研究使我使用了诸如 @auth_token_required 之类的东西,但我在将所有内容放在一起时遇到了一些麻烦。烧瓶安全文档本身并不是很有帮助。

例如,用户如何获得身份验证令牌?什么是身份验证端点?

如果你能带领我朝着正确的方向前进,那就太好了。代码示例也很棒:-)

【问题讨论】:

我担心这样的关键基础设施没有很好的文档记录。 【参考方案1】:

我发现 Flask-Security 的基于令牌的方案不适合我的项目。我建议改用 JWT 令牌。

Flask-Security 基于令牌的身份验证存在的问题。

    需要全局禁用 CSRF,当您还有一个需要 CSRF 令牌的传统 Web 应用程序时,这并不好 没有简单的方法来更新令牌(无需再次提交密码) 无法控制令牌的有效负载,没有 API 可以向令牌发送/获取数据 按照设计,该令牌仅适用于一个 Flask 应用程序。因此,如果您的前端应用需要与多个 restful api 通信,这将无法正常工作

查看 JWT(pyjwt 或 flask-jwt)令牌,它解决了上述所有问题以及更多问题。

【讨论】:

如果你使用 wtforms 你不需要全局禁用 CSRF,你可以在你的 API 视图上使用 @csrf_protect.exempt 装饰器。 @bmjjr 你能详细说明不必禁用 CSRF 吗?如何专门免除 API 登录端点? @jminardi 与 wtforms,例如在 Flask 应用程序中,首先您必须初始化 CSRFProtect 类,然后在其上调用 init_app。我在我的base.extensions.py 文件中使用from flask_wtf import CSRFProtect 执行此操作,然后像csrf_protect = CSRFProtect() 一样对其进行初始化。然后,在create_app() 函数的base.app 文件中,创建flask 应用程序对象,然后在create_app 中调用csrf_protect.init_app(app)。最后,您可以从您的base.extensions 文件中导入csrf_protect,并将其用作API 视图函数上的@csrf_protect.exempt 的装饰器。 我发现使用app.config['WTF_CSRF_ENABLED'] = False 也可以。但是,确实,使用 JWT 可能是更好的选择,或者至少是更标准化的选择。 你在这里比较苹果和香蕉。 flask-security/login 中有很多你在 flask-jwt 中找不到的功能(密码重置、联合、访问列表等)如果你需要有效负载,只需通过覆盖两个相应的方法来使用 jwt在用户模型中。【参考方案2】:

端点是 /login,您将凭据作为 json 请求正文发布:

'email':'john@smit.com', 'password':'1234'

但是,要使其正常工作,您需要在烧瓶应用中禁用 csrf 令牌(感谢 Mandar Vaze):

app.config['WTF_CSRF_ENABLED'] = False

然后,您使用 HTTP 标头中的令牌执行每个请求:

Authentication-Token:WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0

或者作为查询字符串:

http://localhost:5000/protected?auth_token=WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0

python 3 中的客户端示例:

import requests
import json

#do the login
r = requests.post('http://localhost:5000/login', 
                    data=json.dumps('email':'john@smit.com', 'password':'1234'), 
                    headers='content-type': 'application/json')
response = r.json()
print(response) #check response
token = response['response']['user']['authentication_token']    #set token value

#Now you can do authorised calls
r = requests.get('http://localhost:5000/protected', 
                headers='Authentication-Token': token)
print(r.text)

Angular 示例 sn-p 获取令牌:

$http.post('/login', "email": $scope.formdata.login,"password":$scope.formdata.password).
            success(function(results) 
            $window.sessionStorage.token = results.response.user.authentication_token;
            );

Angular 示例 sn-p 访问受保护的页面:

 if ($window.sessionStorage.getItem('token')) 
                config.headers['Authentication-Token'] = $window.sessionStorage.getItem('token');
            

【讨论】:

谢谢。你在生产中使用 Flask-Security 的基于令牌的身份验证吗? 目前只在开发中,我仍然没有明确的答案:在这种情况下我们是否需要 CSRF 来增强安全性?另见:***.com/questions/18436124/flask-security-csrf-token/… 禁用 CSRF 是不可接受的,除非您没有带有表单的 html 视图。 @Sebastian 我可以将roles_accepted 与基于令牌的身份验证结合使用吗? @adnanmuttaleb 抱歉,我不知道那个问题的答案【参考方案3】:

身份验证端点是 /login

具体看flask-securityhere的代码views.py:_render_json()

login() 调用 _render_json,后者又调用 get_auth_token() - 并返回身份验证令牌。

问题(对我来说)是让它发挥作用。 对我来说 request.json 似乎是空的(因此这工作)

"email": "test@example.com", "password": "test123"

希望这可以帮助您前进一点。

【讨论】:

在我的情况下 POST 到 /login 有效,但随后获得的令牌在 Authentication-Token 标头中不起作用。无论如何,您需要检查令牌中的真实内容。在旧版本的 Flask-Security 中,它只是对登录密码进行编码和解码(如果我理解正确的话) - 安全性如此之多。

以上是关于带有烧瓶安全扩展的基于令牌的身份验证的主要内容,如果未能解决你的问题,请参考以下文章

在基于令牌的身份验证中使用刷新令牌是不是安全?

如何在 python 中生成唯一的身份验证令牌?

基于 Token 的身份验证

基于 Token 的身份验证

(转)基于 Token 的身份验证

基于令牌的身份验证和可扩展性?错觉?