基于密码的认证

现在我们假设存在一个资源通过一个 API 暴露给那些必须注册的用户。这个资源是通过 URL: /api/resource 能够访问到。

为了保护这个资源,我们将使用 HTTP 基本身份认证,但是不是自己编写完整的代码来实现它,而是让 Flask-HTTPAuth 扩展来为我们做。

使用 Flask-HTTPAuth,通过添加 login_required 装饰器可以要求相应的路由必须进行认证:

  1. from flask.ext.httpauth import HTTPBasicAuth
  2. auth = HTTPBasicAuth()
  3.  
  4. @app.route('/api/resource')
  5. @auth.login_required
  6. def get_resource():
  7. return jsonify({ 'data': 'Hello, %s!' % g.user.username })

但是,Flask-HTTPAuth 需要给予更多的信息来验证用户的认证,当然 Flask-HTTPAuth 有着许多的选项,它取决于应用程序实现的安全级别。

能够提供最大自由度的选择(可能这也是唯一兼容 PassLib 散列)就是选用 verify_password 回调函数,这个回调函数将会根据提供的 username 和 password 的组合的,返回 True(通过验证) 或者 Flase(未通过验证)。Flask-HTTPAuth 将会在需要验证 username 和 password 对的时候调用这个回调函数。

verify_password 回调函数的实现如下:

  1. @auth.verify_password
    def verify_password(username, password):
    user = User.query.filter_by(username = username).first()
    if not user or not user.verify_password(password):
    return False
    g.user = user
    return True

这个函数将会根据 username 找到用户,并且使用 verify_password() 方法验证密码。如果认证通过的话,用户对象将会被存储在 Flask 的 g 对象中,这样视图就能使用它。

这里是用 curl 请求只允许注册用户获取的保护资源:

  1. $ curl -u miguel:python -i -X GET http://127.0.0.1:5000/api/resource
  2. HTTP/1.0 200 OK
  3. Content-Type: application/json
  4. Content-Length: 30
  5. Server: Werkzeug/0.9.4 Python/2.7.3
  6. Date: Thu, 28 Nov 2013 20:02:25 GMT
  7.  
  8. {
  9. "data": "Hello, miguel!"
  10. }

如果登录失败的话,会得到下面的内容:

  1. $ curl -u miguel:ruby -i -X GET http://127.0.0.1:5000/api/resource
  2. HTTP/1.0 401 UNAUTHORIZED
  3. Content-Type: text/html; charset=utf-8
  4. Content-Length: 19
  5. WWW-Authenticate: Basic realm="Authentication Required"
  6. Server: Werkzeug/0.9.4 Python/2.7.3
  7. Date: Thu, 28 Nov 2013 20:03:18 GMT
  8.  
  9. Unauthorized Access

这里我再次重申在实际的应用中,请使用安全的 HTTP。