Restful API不保存状态,无法依赖Cookie及Session来保存用户信息,自然也无法使用Flask-Login扩展来实现用户认证。所以这里,我们就要介绍另一个扩展,Flask-HTTPAuth。

pip install flask-httpauth

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

from flask import Flask
from flask_httpauth import HTTPBasicAuth app = Flask(__name__)
auth = HTTPBasicAuth()

注意,初始化实例时不需要传入app对象,也不需要调用”auth.init_app(app)”注入应用对象。另外,Flask-HTTPAuth提供了几种不同的Auth方法,比如HTTPBasicAuth,HTTPTokenAuth,MultiAuth和HTTPDigestAuth。上例中我们使用了HTTPBasicAuth,下文中也会分别介绍HTTPTokenAuth和MultiAuth

用户名及密码验证

我们所要做的,就是实现一个根据用户名获取密码的回调函数:

users = [
{'username': 'Tom', 'password': ''},
{'username': 'Michael', 'password': ''}
] @auth.get_password
def get_password(username):
for user in users:
if user['username'] == username:
return user['password']
return None

回调函数”get_password()”由装饰器”@auth.get_password”修饰。在函数里,我们根据传入的用户名,返回其密码;如果用户不存在,则返回空。接下来,我们就可以在任一视图函数上,加上”@auth.login_required”装饰器,来表示该视图需要认证:

@app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % auth.username()

启动该应用,当你在浏览器里打开”http://localhost:5000/”,你会发现浏览器跳出了下面的登录框,输入正确的用户名密码(比如上例中的Tom:111111)后,”Hello Tom!”的字样才会显示出来。

进入浏览器调试,发现认证并没有启用Cookie,而是在请求头中加上了加密后的认证字段:

Authorization: Basic TWljaGFlbDoxMjM0NTY=

这就是”HTTPBasicAuth”认证的功能,你也可以用Curl命令来测试:

curl -u Tom:111111 -i -X GET http://localhost:5000/

非明文密码

上例中”@auth.get_password”回调只对明文的密码有效,但是大部分情况,我们的密码都是经过加密后才保存的,这时候,我们要使用另一个回调函数”@auth.verify_password”。在演示代码之前,先要介绍Werkzeug库里提供的两个方法:

  • generate_password_hash: 对于给定的字符串,生成其加盐的哈希值
  • check_password_hash: 验证传入的哈希值及明文字符串是否相符

这两个方法都在”werkzeug.security”包下。现在,我们要利用这两个方法,来实现加密后的用户名密码验证:

from werkzeug.security import generate_password_hash, check_password_hash

users = [
{'username': 'Tom', 'password': generate_password_hash('')},
{'username': 'Michael', 'password': generate_password_hash('')}
] @auth.verify_password
def verify_password(username, password):
for user in users:
if user['username'] == username:
if check_password_hash(user['password'], password):
return True
return False

在”@auth.verify_password”所修饰的回调函数里,我们验证传入的用户名密码,如果正确的话返回True,否则就返回False。

错误处理

在之前的例子中,如果未认证成功,服务端会返回401状态码及”Unauthorized Access”文本信息。你可以重写错误处理方法,并用”@auth.error_handler”装饰器来修饰它:

from flask import make_response, jsonify

@auth.error_handler
def unauthorized():
return make_response(jsonify({'error': 'Unauthorized access'}), 401)

有了上面的”unauthorized()”方法后,如果认证未成功,服务端返回401状态码,并返回JSON信息”{‘error’: ‘Unauthorized access’}”。

令牌(Token)认证

在对HTTP形式的API发请求时,大部分情况我们不是通过用户名密码做验证,而是通过一个令牌,也就是Token来做验证。此时,我们就要请出Flask-HTTPAuth扩展中的HTTPTokenAuth对象。

同HTTPBasicAuth类似,它也提供”login_required”装饰器来认证视图函数,”error_handler”装饰器来处理错误。区别是,它没有”verify_password”装饰器,相应的,它提供了”verify_token”装饰器来验证令牌。我们来看下代码,为了简化,我们将Token与用户的关系保存在一个字典中:

from flask import Flask, g
from flask_httpauth import HTTPTokenAuth app = Flask(__name__)
auth = HTTPTokenAuth(scheme='Bearer') tokens = {
"secret-token-1": "John",
"secret-token-2": "Susan"
} @auth.verify_token
def verify_token(token):
g.user = None
if token in tokens:
g.user = tokens[token]
return True
return False @app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % g.user

可以看到,在”verify_token()”方法里,我们验证传入的Token是否合法,是的话返回True,否则返回False。另外,我们通过Token获取了用户信息,并保存在全局变量g中,这样视图中可以获取它。注意,在第一节的例子中,我们使用了”auth.username()”来获取用户名,但这里不支持。

初始化HTTPTokenAuth对象时,我们传入了”scheme=’Bearer'”。这个scheme,就是我们在发送请求时,在HTTP头”Authorization”中要用的scheme字段。

启动上面的代码,并用Curl命令来测试它:

curl -X GET -H "Authorization: Bearer secret-token-1" http://localhost:5000/

HTTP头信息”Authorization: Bearer secret-token-1″,”Bearer”就是指定的scheme,”secret-token-1″就是待验证的Token。在上例中,”secret-token-1″对应着用户名”John”,所以Token验证成功,Curl命令会返回响应内容”Hello, John!”。

使用itsdangerous库来管理令牌

itsdangerous库提供了对信息加签名(Signature)的功能,我们可以通过它来生成并验证令牌。使用前,先记得安装”pip install itsdangerous”。现在,让我们先来产生令牌,并打印出来看看:

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
serializer = Serializer(app.config['SECRET_KEY'], expires_in=1800) users = ['John', 'Susan']
for user in users:
token = serializer.dumps({'username': user})
print('Token for {}: {}\n'.format(user, token))

这里实例化了一个针对JSON的签名序列化对象serializer,它是有时效性的,30分钟后序列化后的签名即会失效。让我们运行下程序,在控制台上,会看到类似下面的内容:

Token for John: eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ2MzUzMzY4MCwiaWF0IjoxNDYzNTMxODgwfQ.eyJ1c2VybmFtZSI6IkpvaG4ifQ.ox-64Jbd2ngjQMV198nHYUsJ639KIZS6RJl48tC7-DU

Token for Susan: eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ2MzUzMzY4MCwiaWF0IjoxNDYzNTMxODgwfQ.eyJ1c2VybmFtZSI6IlN1c2FuIn0.lRx6Z4YZMmjCmga7gs84KB44UIadHYRnhOr7b4AAKwo

接下来,改写”verify_token()”方法:

@auth.verify_token
def verify_token(token):
g.user = None
try:
data = serializer.loads(token)
except:
return False
if 'username' in data:
g.user = data['username']
return True
return False

我们通过序列化对象的”load()”方法,将签名反序列化为JSON对象,也就是Python里的字典。然后获取字典中的用户名,如果成功则返回True,否则返回False。这样,就实现了加密后的令牌认证了,让我们用Curl测试一下,还记得刚才控制台上打印出的令牌吗?

curl -X GET -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsImV4cCI6MTQ2MzUzMzY4MCwiaWF0IjoxNDYzNTMxODgwfQ.eyJ1c2VybmFtZSI6IkpvaG4ifQ.ox-64Jbd2ngjQMV198nHYUsJ639KIZS6RJl48tC7-DU" http://localhost:5000/

多重认证

Flask-HTTPAuth扩展还支持几种不同认证的组合,比如上面我们介绍了HTTPBasicAuth和HTTPTokenAuth,我们可以将两者组合在一起,其中任意一个认证通过,即可以访问应用视图。实现起来也很简单,只需将不同的认证实例化为不同的对象,并将其传入MultiAuth对象即可。大体代码如下:

from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth

...

basic_auth = HTTPBasicAuth()
token_auth = HTTPTokenAuth(scheme='Bearer')
multi_auth = MultiAuth(basic_auth, token_auth) ... @basic_auth.verify_password
... @token_auth.verify_token
... @basic_auth.error_handler
... @token_auth.error_handler
... @app.route('/')
@multi_auth.login_required
def index():
return 'Hello, %s!' % g.user

这里,每个认证都有自己的验证和错误处理函数,不过在视图上,我们使用”@multi_auth.login_required”来实现多重认证。大家可以使用Curl命令试验下。

RESTFul扩展集成

将上面HTTP认证方法,加入到RESTful API中去,先取回Flask-RESTful扩展的示例代码,再把上例中的认证代码,就HTTPTokenAuth部分吧,加上去。现在关键时刻到了,使用Flask-RESTful扩展时,我们并没有声明视图函数,那该怎么把”@auth.login_required”装饰器加到API视图中去呢?我们来看下代码:

...

class User(Resource):
decorators = [auth.login_required]
... class UserList(Resource):
decorators = [auth.login_required]
...

很简单吧,只需要在Resource类中,加上”decorators=[…]”的声明,就可以注入视图装饰器,而且可以同时注入多个

Flask 扩展 HTTP认证的更多相关文章

  1. Flask扩展实现HTTP令牌token认证HTTPTokenAuth

    Token认证 在restful设计中,用户认证模式通常使用json web token,而不会使用传统的HTTP Basic认证(传入账号密码) token认证模式如下:在请求header中加入to ...

  2. Flask从入门到精通之flask扩展

    Flask被设计成可扩展形式,因此并没有提供一些重要的功能,比如数据库和用户认证,所以开发者可以自由选择最适合程序的包,或者按需求自行开发.社区成员开发了大量不同用途的扩展,如果这还不能满足需求,你还 ...

  3. 2.6、Flask扩展

    Flask 被设计为可扩展形式,故而没有提供一些重要的功能,例如数据库和用户认证,所以开发者可以自由选择最适合程序的包,或者按需求自行开发. 社区成员开发了大量不同用途的扩展,如果这还不能满足需求,你 ...

  4. 使用Flask设计带认证token的RESTful API接口

    大数据时代 Just a record. 使用Flask设计带认证token的RESTful API接口[翻译] 上一篇文章, 使用python的Flask实现一个RESTful API服务器端  简 ...

  5. Inside Flask - flask 扩展加载过程

    Inside Flask - flask 扩展加载过程 flask 扩展(插件)通常是以 flask_<扩展名字> 为扩展的 python 包名,而使用时,可用 import flask. ...

  6. Flask從入門到入土(二)——請求响应與Flask扩展

    ———————————————————————————————————————————————————————————— 一.程序和請求上下文 Flask從客戶端收到請求時,要讓視圖函數能訪問一些對象 ...

  7. Flask 扩展 自定义扩展

    创建一个为视图访问加日志的扩展Flask-Logging,并从中了解到写Flask扩展的规范. 创建工程 先创建一个工程,目录结构如下: flask-logging/ ├ LICENSE # 授权说明 ...

  8. Laravel核心解读 -- 扩展用户认证系统

    扩展用户认证系统 上一节我们介绍了Laravel Auth系统实现的一些细节知道了Laravel是如何应用看守器和用户提供器来进行用户认证的,但是针对我们自己开发的项目或多或少地我们都会需要在自带的看 ...

  9. Flask基础(13)-->Flask扩展Flask-Script

    Flask基础(12)-->Flask扩展Flask-Script # 前提是安装了Flask-Script # 联网运行 pip install flask-script from flask ...

随机推荐

  1. Babel 安装教程

    Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行. 这意味着,你可以现在就用 ES6 编写程序,而不用担心现有环境是否支持.下面是一个例子. // 转码前 inpu ...

  2. Android中selector的使用

    第一种方法(强烈推荐) 方法:selector做遮罩,原图做background. 我们做按钮的时候经常需要用两个图片来实现按钮点击和普通状态的样式,这就需要提供两种图片,而且每个分辨率下还有多套图片 ...

  3. 【Luogu1879】玉米田(状态压缩,动态规划)

    懒得搞题目了 哦对了,这题双倍经验 题解 装压DP 利用位运算很容易解决相邻位的问题 其实我的还是太复杂了 具体的,更加好的位运算的写法可以参考YL大佬,但是我也搞不到他代码,因为他太强了. 然而他博 ...

  4. css实现文本缩略显示

    转载自http://blog.csdn.net/mushui0633/article/details/65685655 单行: 对应的css中加入 overflow:hidden;//超出一行文字自动 ...

  5. java支付宝开发-02-手机网站支付

    源码已上传github,欢迎专注:https://github.com/shirayner/alipay-wap 一.基础部分 1.手机网站支付产品介绍 1.1 阅读官方介绍: 手机网站支付产品介绍 ...

  6. Spring9:Autowire(自动装配)机制

    为什么Spring要支持Autowire(自动装配) 先写几个类,首先定义一个Animal接口表示动物: public interface Animal { public void eat(); } ...

  7. C#多线程之异步编程

    c#中异步编程,主要有两种方法: 1.委托的异步调用: 2.Task的await,async (c# 4.5) 我们来看例子: /// <summary> /// 异步保存网页,url:网 ...

  8. 制作windows系统合盘:把win7和win8/8.1打包在一起

    平时装系统的时候我比较喜欢win8.1,但是经常给别人装系统的时候别人很多都喜欢win7,但是我觉得这样很麻烦,于是就想做一个合盘,这样就很方便了,win7旗舰版里面其实封装了四个系统,或者说一个系统 ...

  9. Unity的常用API

    1.Event Function:事件函数   Reset() :被附加脚本时.在游戏物体的组件上按Reset时会触发该事件函数 Start() :在游戏初始化时会执行一次 Update() :每一帧 ...

  10. 笔记:Spring Boot 配置详解

    Spring Boot 针对常用的开发场景提供了一系列自动化配置来减少原本复杂而又几乎很少改动的模板配置内容,但是,我们还是需要了解如何在Spring Boot中修改这些自动化的配置,以应对一些特殊场 ...