基于Flask的 api(四)
restful安全认证
Flask-HTTPAuth是一个简单的扩展,它简化了使用Flask路由的HTTP身份验证的使用
pip install Flask-HTTPAuth
认证方式有 Basic 、Digest、token
1.Basic认证
使用HTTP基本身份验证来保护路由
from flask import Flask,jsonify
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
auth = HTTPBasicAuth()
users = {
"aaa": generate_password_hash("123"),
"bbb": generate_password_hash("456")
}
@auth.verify_password
def verify_password(username, password):
if username in users and \
check_password_hash(users.get(username), password):
return username
@app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % auth.current_user()
if __name__ == "__main__":
app.run(debug=True)
测试
$ curl -i http://localhost:5000
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 19 100 19 0 0 81 0 --:--:-- --:--:-- --:--:-- 81HTTP/1.0 401 UNAUTHORIZED
Content-Type: text/html; charset=utf-8
Content-Length: 19
WWW-Authenticate: Basic realm="Authentication Required"
Server: Werkzeug/1.0.1 Python/3.6.0
Date: Mon, 23 Nov 2020 15:24:26 GMT
Unauthorized Access
使用curl时添加 -u (或 - user )
$ curl -u aaa:123 -i http://localhost:5000
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 11 100 11 0 0 15 0 --:--:-- --:--:-- --:--:-- 15HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 11
Server: Werkzeug/1.0.1 Python/3.6.0
Date: Mon, 23 Nov 2020 15:24:44 GMT
Hello, aaa!
将验证添加到获取资源上
from flask import Flask,jsonify
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
auth = HTTPBasicAuth()
users = {
"aaa": generate_password_hash("123"),
"bbb": generate_password_hash("456")
}
@auth.verify_password
def verify_password(username, password):
if username in users and \
check_password_hash(users.get(username), password):
return username
@app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % auth.current_user()
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good Python tutorial on the web',
'done': False
}
]
@app.route("/tasks", methods=['GET'])
@auth.login_required
def get_tasks():
return jsonify({'tasks': tasks})
if __name__ == "__main__":
app.run(debug=True)
测试
$ curl -i http://localhost:5000/tasks
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 19 100 19 0 0 80 0 --:--:-- --:--:-- --:--:-- 80HTTP/1.0 401 UNAUTHORIZED
Content-Type: text/html; charset=utf-8
Content-Length: 19
WWW-Authenticate: Basic realm="Authentication Required"
Server: Werkzeug/1.0.1 Python/3.6.0
Date: Mon, 23 Nov 2020 15:33:14 GMT
Unauthorized Access
Bei@DESKTOP-LCBJFJ2 MINGW64 /d/Python/dxfWrite
$ curl -u aaa:123 -i http://localhost:5000/tasks
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 317 100 317 0 0 751 0 --:--:-- --:--:-- --:--:-- 751HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 317
Server: Werkzeug/1.0.1 Python/3.6.0
Date: Mon, 23 Nov 2020 15:33:19 GMT
{
"tasks": [
{
"description": "Milk, Cheese, Pizza, Fruit, Tylenol",
"done": false,
"id": 1,
"title": "Buy groceries"
},
{
"description": "Need to find a good Python tutorial on the web",
"done": false,
"id": 2,
"title": "Learn Python"
}
]
}
2.Digest
使用HTTP摘要式身份验证
from flask import Flask,jsonify
from flask_httpauth import HTTPDigestAuth
app = Flask(__name__)
app.config['SECRET_KEY'] = 'key123456'
auth = HTTPDigestAuth()
users = {
"aaa": "123",
"bbb": "456"
}
@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None
@app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % auth.username()
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good Python tutorial on the web',
'done': False
}
]
@app.route("/tasks", methods=['GET'])
@auth.login_required
def get_tasks():
return jsonify({'tasks': tasks})
if __name__ == "__main__":
app.run(debug=True)
测试
说明:
a.客户端访问一个受http摘要认证保护的资源
b.服务器返回401状态以及nonce等信息,要求客户端进行认证
c.客户端将以用户名,密码,nonce值,HTTP方法, 和被请求的URI为校验值基础而加密(默认为MD5算法)的摘要信息返回给服务器
d.如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证
3.token
from flask import Flask, g,jsonify from flask_httpauth import HTTPTokenAuth app = Flask(__name__) auth = HTTPTokenAuth(scheme='Bearer') tokens = { "token1": "aaa", "token2": "bbb" } @auth.verify_token def verify_token(token): if token in tokens: return tokens[token] @app.route('/') @auth.login_required def index(): return "Hello, {}!".format(auth.current_user()) tasks = [ { 'id': 1, 'title': u'Buy groceries', 'description': u'Milk, Cheese, Pizza, Fruit, Tylenol', 'done': False }, { 'id': 2, 'title': u'Learn Python', 'description': u'Need to find a good Python tutorial on the web', 'done': False } ] @app.route("/tasks", methods=['GET']) @auth.login_required def get_tasks(): return jsonify({'tasks': tasks}) if __name__ == '__main__': app.run(debug=True)
测试