WEB身份认证
WEB身份认证是网页开发的重要技术,是服务端对于客户端的用户身份进行真实性、有效性的鉴别和标识等的基本操作。本文主要介绍3种常见的身份验证方式,以及python的实现demo。
HTTP身份验证
HTTP协议内的基本身份验证是最基础的形式,用户输入用户名和密码,客户端将身份信息用base64进行编码,包装在标头随每一次请求发送到服务端。这种方法是无状态的,适用于API调用和不需要持久会话的身份验证。
其工作流如下图:
优点:
简单快速,易实施。
支持所有主流浏览器。
缺点:
未加密处理,纯文本传输,安全性较差。
无状态必须随每个请求发送凭据。
只能通过使用无效凭据重写来注销。
代码:实例利用Flask-HTTP包实现
from flask import Flask
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__)
auth = HTTPBasicAuth()
users = {
#自定义用户列表字典
"username":"password",
}
@auth.verify_password
def verify_password(username, password):
if username in users and password==users[username]):
return username
@app.route("/")
@auth.login_required
def index():
return f"You have successfully logged in, {auth.current_user()}"
if __name__ == "__main__":
app.run()
基于Cookie的身份验证
会话验证即为我们最常见到的Cookie身份验证。在用户成功登录验证后,服务器将会生产一个会话,并把会话ID返回给浏览器,浏览器将ID保存在本地,在后续的请求中便不再需要发送用户名和密码,只需要发送包含身份认证信息的sessionID即可。
其工作流如下:
优点:
后续登录便捷
多框架可用
缺点:
有状态于服务器端,需要多服务共享会话存储才可启动,不适用于RESTful服务。
cookie不需要身份验证,易受CSRF攻击。
代码:实例利用Flask-Login实现
from flask import Flask, request
from flask_login import (
LoginManager,
UserMixin,
current_user,
login_required,
login_user,
)
app = Flask(__name__)
app.config.update(
SECRET_KEY="change_this_key",
)
login_manager = LoginManager()
login_manager.init_app(app)
users = {
"username": "password",
}
class User(UserMixin):
...
@login_manager.user_loader
def user_loader(username: str):
if username in users:
user_model = User()
user_model.id = username
return user_model
return None
@app.route("/login", methods=["POST"])
def login_page():
data = request.get_json()
username = data.get("username")
password = data.get("password")
if username in users:
if password==users[username]:
user_model = User()
user_model.id = username
login_user(user_model)
else:
return "Wrong credentials"
return "logged in"
@app.route("/")
@login_required
def protected():
return f"Current user: {current_user.id}"
if __name__ == "__main__":
app.run()
基于Token的身份验证
即用户正常登录并验证成功后,服务端会依据规则生产一串Token字符串作为身份凭证,返回并保留在客户端。客户端在后续访问服务端时携带Token,服务端根据规则解读Token进行验证身份。
工作流如下图:
优点:
使用签名便可完成认证,验证速度快。
适用于多个服务共享身份认证的场景。
缺点:
令牌在客户端的保存方式可能会导致XSS攻击。
令牌只能过期不能删除,被暴露后在失效前都可能会被滥用。
代码:实例以Flask-JWT为例
from flask import Flask, request, jsonify
from flask_jwt_extended import (
JWTManager,
jwt_required,
create_access_token,
get_jwt_identity,
)
app = Flask(__name__)
app.config.update(
JWT_SECRET_KEY="please_change_this",
)
jwt = JWTManager(app)
users = {
"username": "password",
}
@app.route("/login", methods=["POST"])
def login_page():
username = request.json.get("username")
password = request.json.get("password")
if username in users:
if password==users[username]:
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token), 200
return "Wrong credentials", 400
@app.route("/")
@jwt_required
def protected():
return jsonify(logged_in_as=get_jwt_identity()), 200
if __name__ == "__main__":
app.run()
总结:
身份验证方法 |
优点 |
缺点 |
是否有状态 |
HTTP身份验证 |
简单易操作 | 密码文本传输,安全性较差 | 无状态 |
Cookie身份验证 | 保持会话,后续登录便捷 | 易受CSRF攻击 | 有状态 |
Token身份验证 | 利用签名验证,请求速度快 | 易受XSS攻击,令牌失效前易被滥用。 | 无状态 |