需求
一般我们使用Flask进行前后端分离开发的时候,前端与后端直接就是通过 API 请求进行数据交互,那么我们可以如何去确认我们的服务是安全的呢?
如果是前后端不分离的单体应用中,用户登陆一般是通过填写页面表单,并且在页面配置 csrftoken 来保证该页面为服务页面,然后登陆成功之后,将用户的登陆状态保存在服务器的session中,然后session_id 以 cookie 存储在浏览器端。
在前后端分离的开发中,我们一般会基于 REST 的规则设计 API,而单纯的 HTTP 请求是无状态的,要求浏览器客户端在每一次请求都要提供认证的信息,那么怎么去便利地让 HTTP 提供认证呢?
HTTP 协议提供了两种认证机制:Basic 和 Digest。
而在 Flask 框架中,有一个库Flask-HTTPAuth
可以让我们很方便实现这两个认证功能,下面来示例演示一下。
安装 Flask-HTTPAuth
Github地址:https://github.com/miguelgrinberg/Flask-HTTPAuth
使用 pip 库安装:
代码语言:javascript复制pip install Flask-HTTPAuth
Basic authentication 基础认证示例
示例代码
代码语言:javascript复制from flask import Flask, jsonify, make_response
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
auth = HTTPBasicAuth()
# 用户的名称以及密码
users = {
"john": generate_password_hash("hello"),
"susan": generate_password_hash("bye")
}
@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()
# 自定义未认证通过的返回
@auth.error_handler
def unauthorized():
# return make_response(jsonify({'error': 'Unauthorized access'}), 401)
return make_response(jsonify({'error': 'Unauthorized access'}), 403) # 403 禁止
if __name__ == '__main__':
app.run()
启动服务后,使用POSTMAN测试如下:
- 认证成功
image-20200918152426433
- 认证失败
image-20200918152444962
使用 Curl 的方式测试如下:
认证成功
代码语言:javascript复制[root@dev ~]# curl -u john:hello -i http://127.0.0.1:5000/
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 12
Server: Werkzeug/1.0.1 Python/3.7.1
Date: Fri, 18 Sep 2020 07:34:14 GMT
Hello, john![root@dev ~]#
认证失败
代码语言:javascript复制[root@dev ~]# curl -u jo:hello -i http://127.0.0.1:5000/
HTTP/1.0 403 FORBIDDEN
Content-Type: application/json
Content-Length: 32
WWW-Authenticate: Basic realm="Authentication Required"
Server: Werkzeug/1.0.1 Python/3.7.1
Date: Fri, 18 Sep 2020 07:34:42 GMT
{"error":"Unauthorized access"}
[root@dev ~]#
Digest authentication 摘要认证示例
示例代码
代码语言:javascript复制from flask import Flask, jsonify, make_response
from flask_httpauth import HTTPDigestAuth
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
auth = HTTPDigestAuth()
users = {
"john": "hello",
"susan": "bye"
}
@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()
# 自定义未认证通过的返回
@auth.error_handler
def unauthorized():
# return make_response(jsonify({'error': 'Unauthorized access'}), 401)
return make_response(jsonify({'error': 'Unauthorized access'}), 403) # 403 禁止
if __name__ == '__main__':
app.run(host="0.0.0.0", port="5000", debug=True)
启动服务后,使用POSTMAN测试如下:
- 认证成功
image-20200918155240399
- 认证失败
image-20200918155258499