原文链接: flask 简单flask-httpauth验证
上一篇: Python flask 在请求前拦截
下一篇: es 6 对象操作
确保我们的 web service 安全服务的最简单的方法是要求客户端提供一个用户名和密码。在常规的 web 应用程序会提供一个登录的表单用来认证,并且服务器会创建一个会话为登录的用户以后的操作使用,会话的 id 以 cookie 形式存储在客户端浏览器中。然而 REST 的规则之一就是 “无状态”, 因此我们必须要求客户端在每一次请求中提供认证的信息。
我们一直试着尽可能地坚持 HTTP 标准协议。既然我们需要实现认证我们需要在 HTTP 上下文中去完成,HTTP 协议提供了两种认证机制: Basic 和 Digest 。
有一个小的 Flask 扩展能够帮助我们,我们可以先安装 Flask-HTTPAuth:
$ flask/bin/pip install flask-httpauth
比方说,我们希望我们的 web service 只让访问用户名 miguel 和密码 python 的客户端访问。 我们可以设置一个基本的 HTTP 验证如下:
from flask.ext.httpauth import HTTPBasicAuth auth = HTTPBasicAuth() @auth.get_password def get_password(username): if username == 'miguel': return 'python' return None @auth.error_handler def unauthorized(): return make_response(jsonify({'error': 'Unauthorized access'}), 401)
get_password 函数是一个回调函数,Flask-HTTPAuth 使用它来获取给定用户的密码。在一个更复杂的系统中,这个函数是需要检查一个用户数据库,但是在我们的例子中只有单一的用户因此没有必要。
error_handler 回调函数是用于给客户端发送未授权错误代码。像我们处理其它的错误代码,这里我们定制一个包含 JSON 数据格式而不是 HTML 的响应。
随着认证系统的建立,所剩下的就是把需要认证的函数添加 @auth.login_required 装饰器。例如:
@app.route('/todo/api/v1.0/tasks', methods=['GET']) @auth.login_required def get_tasks(): return jsonify({'tasks': tasks})
如果现在要尝试使用 curl 调用这个函数我们会得到:
$ curl -i http://localhost:5000/todo/api/v1.0/tasks HTTP/1.0 401 UNAUTHORIZED Content-Type: application/json Content-Length: 36 WWW-Authenticate: Basic realm="Authentication Required" Server: Werkzeug/0.8.3 Python/2.7.3 Date: Mon, 20 May 2013 06:41:14 GMT { "error": "Unauthorized access" }
为了能够调用这个函数我们必须发送我们的认证凭据:
$ curl -u miguel:python -i http://localhost:5000/todo/api/v1.0/tasks HTTP/1.0 200 OK Content-Type: application/json Content-Length: 316 Server: Werkzeug/0.8.3 Python/2.7.3 Date: Mon, 20 May 2013 06:46:45 GMT { "tasks": [ { "title": "Buy groceries", "done": false, "description": "Milk, Cheese, Pizza, Fruit, Tylenol", "uri": "http://localhost:5000/todo/api/v1.0/tasks/1" }, { "title": "Learn Python", "done": false, "description": "Need to find a good Python tutorial on the web", "uri": "http://localhost:5000/todo/api/v1.0/tasks/2" } ] }
认证扩展给予我们很大的自由选择哪些函数需要保护,哪些函数需要公开。
为了确保登录信息的安全应该使用 HTTP 安全服务器(例如: https:// ...),这样客户端和服务器之间的通信都是加密的,以防止传输过程中第三方看到认证的凭据。
让人不舒服的是当请求收到一个 401 的错误,网页浏览都会跳出一个丑陋的登录框,即使请求是在后台发生的。因此如果我们要实现一个完美的 web 服务器的话,我们就需要禁止跳转到浏览器显示身份验证对话框,让我们的客户端应用程序自己处理登录。
一个简单的方式就是不返回 401 错误。403 错误是一个令人青睐的替代,403 错误表示 “禁止” 的错误:
@auth.error_handler def unauthorized(): return make_response(jsonify({'error': 'Unauthorized access'}), 403)
from flask_httpauth import HTTPBasicAuth
auth = HTTPBasicAuth()
from flask import Flask, make_response, jsonify
app = Flask(__name__)
@auth.get_password
def get_password(username):
if username == 'miguel':
return 'python'
return None
@auth.error_handler
def unauthorized():
return make_response(jsonify({'error': 'Unauthorized access'}), 401)
@app.route('/', methods=['GET'])
@auth.login_required
def get_tasks():
return jsonify({'tasks': 'succ'})
app.run(port=80)