导言
有些网站在打开时就会弹出登录提示框,直接提示你输入用户名和密码,验证成功才能查看页面。这样的验证使用的是HTTPAuth验证方式,如果想在自己的网站设置这样的验证就需要使用Python模块flask_HTTPAuth,下面我们就来详细看一下这个模块的使用。
flask_httpauth模块封装了以下几种简单的认证方式:基本认证(Basic Authentication),摘要认证(Digest Authentication),标志认证(Token Authentication)。
基本认证
为了保护根路径,下面的例子使用基本认证。
代码语言:javascript复制 from flask import Flask
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__)
auth = HTTPBasicAuth()
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()
if __name__ == '__main__':
app.run()
调用get_password方法时需要返回一个和用户名相关联的密码,当且仅当get_password(用户名) == 密码时验证才通过。
如果密码以哈希的方式存储在用户数据库中,那么就需要调用另一个方法。
代码语言:javascript复制 @auth.hash_password
def hash_pw(password):
return md5(password).hexdigest()
当且仅当get_password(用户名) == hash_password(密码)时验证才会通过。
如果哈希算法要求知道用户名,那么调用的时候可以携带两个参数而不是一个参数:
代码语言:javascript复制 @auth.hash_password
def hash_pw(username, password):
salt = get_salt(username)
return hash(password, salt)
从灵活性的角度考虑,get_password和hash_password两个方法可以统一的替代为verify_password方法:
代码语言:javascript复制 @auth.verify_password
def verify_pw(username, password):
return call_custom_verify_function(username, password)
摘要认证
接下来的例子和上面的差不多,但是使用的是摘要认证:
代码语言:javascript复制 from flask import Flask
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()
if __name__ == '__main__':
app.run()
关于摘要认证的安全
摘要认证算法要求发送一个口令到客户端用来加密密码为了安全的传输。当密码在服务器解密时口令需要再次被使用。所以,口令信息需要被保存便于以后重新调用。
默认情况下,口令被保存在Flask会话中,当使用会话存储时,为了确保更安全的传输,要求服务器端的会话被使用而不是使用默认的基于会话的Flask的cookie,因为这可以确保当口令在传输过程中不会被截获。Flask-Session和Flask-KVSession扩展包是实现服务端会话的良好的选择。
作为使用服务器端会话的替代方案,应用程序可以实现自己的口令数据生成和存储。为此,应用程序需要实现四个回调函数:
代码语言:javascript复制 @auth.generate_nonce
def generate_nonce():
"""返回要用于此客户端的当前值。"""
pass
@auth.generate_opaque
def generate_opaque():
"""返回要用于此客户端的不透明值。"""
pass
@auth.verify_nonce
def verify_nonce(nonce):
"""验证客户端发送的当前值是否正确。"""
pass
@auth.verify_opaque
def verify_opaque(opaque):
"""验证客户端发送的不透明值是否正确。"""
pass
想知道当前值和不透明值是什么以及如何在摘要认证中使用它们,参考:http://tools.ietf.org/html/rfc2617#section-3.2.1。
标志认证
接下来的例子使用一个自定义的通过一个标志保护根路径的HTTP认证方式:
代码语言:javascript复制 from flask import Flask, g
from flask_httpauth import HTTPTokenAuth
app = Flask(__name__)
auth = HTTPTokenAuth(scheme='Token')
tokens = {
"secret-token-1": "john",
"secret-token-2": "susan"
}
@auth.verify_token
def verify_token(token):
if token in tokens:
g.current_user = tokens[token]
return True
return False
@app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % g.current_user
if __name__ == '__main__':
app.run()
HTTPTokenAuth一种通用身份验证处理程序,可与非标准身份验证方案一起使用,其方案名称作为构造函数中的参数。在上面的例子中,由服务器提供的WWW-验证头将会使用Token作为解决方案:
代码语言:javascript复制 WWW-Authenticate: Token realm="Authentication Required"
调用verify_token在验证头接收客户端提供的身份验证凭据。这可以是一个简单的东西,或者可以包含多个函数必须解析并从字符串中提取的参数。