目录
[1. 基础认证原理](#1. 基础认证原理)
[2. 三种实现方案](#2. 三种实现方案)
[2.1 方案一:使用标准库手动实现](#2.1 方案一:使用标准库手动实现)
[2.2 方案二:使用Flask和flask_httpauth库](#2.2 方案二:使用Flask和flask_httpauth库)
[2.3 方案三:增强安全性(存储密码哈希)](#2.3 方案三:增强安全性(存储密码哈希))
[3. 重要安全提醒](#3. 重要安全提醒)
[4. 总结](#4. 总结)
为Python HTTP服务器添加用户名密码认证是保护内容的好方法。以下是几种从简单到实用的实现方案。
1. 基础认证原理
HTTP Basic Authentication(基础认证)的原理是:客户端请求时,服务器检查认证信息。若未提供,返回401 Unauthorized状态码和WWW-Authenticate头部,提示需要认证。浏览器会弹出对话框让用户输入用户名和密码。客户端将用户名和密码用冒号连接后,进行Base64编码,然后在下次请求的Authorization头部中发送给服务器。服务器解码并验证凭据,通过则返回资源,否则返回错误。
2. 三种实现方案
您可以根据需求选择以下方案:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 标准库手动实现 | 无需额外依赖;理解底层机制 | 代码量稍大;安全性需自行处理 | 学习原理;轻量级临时使用 |
| Flask + flask_httpauth | 代码简洁;功能完善;安全性好 | 需安装Flask框架 | 大多数需要认证的Web应用 |
| 密码哈希增强 | 存储更安全;防止密码泄露 | 增加轻微复杂度 | 任何存储用户密码的场景 |
2.1 方案一:使用标准库手动实现
这种方法直接使用Python内置的http.server模块,适合理解认证流程。
python
from http.server import HTTPServer, BaseHTTPRequestHandler
import base64
# 预定义合法的用户名和密码
VALID_USERNAME = 'admin'
VALID_PASSWORD = 'password123'
class AuthHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
# 1. 调用认证检查
if not self.authenticate():
return # 认证失败,方法已处理响应
# 2. 认证成功,返回受保护的内容
self.send_response(200)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(f'<h1>你好,{VALID_USERNAME}!认证成功。</h1>'.encode('utf-8'))
def authenticate(self):
"""处理认证逻辑"""
auth_header = self.headers.get('Authorization')
# 2.1 检查请求头是否包含认证信息
if not auth_header:
self.send_authentication_required() # 发送401要求认证
return False
try:
# 2.2 解析和验证凭证
auth_type, encoded_credentials = auth_header.split(' ', 1)
if auth_type.lower() != 'basic':
self.send_authentication_required()
return False
decoded_bytes = base64.b64decode(encoded_credentials)
decoded_str = decoded_bytes.decode('utf-8')
username, password = decoded_str.split(':', 1)
if username == VALID_USERNAME and password == VALID_PASSWORD:
return True # 认证通过
else:
self.send_forbidden() # 凭证错误,发送403
return False
except Exception as e:
self.send_forbidden()
return False
def send_authentication_required(self):
"""发送401认证要求响应"""
self.send_response(401)
self.send_header('WWW-Authenticate', 'Basic realm="Secure Area"')
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(b'<h1>401 - 需要认证</h1>')
def send_forbidden(self):
"""发送403禁止访问响应"""
self.send_response(403)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(b'<h1>403 - 用户名或密码错误</h1>')
if __name__ == '__main__':
server_address = ('', 8080)
httpd = HTTPServer(server_address, AuthHTTPRequestHandler)
print('服务器运行在 http://localhost:8080')
httpd.serve_forever()
2.2 方案二:使用Flask和flask_httpauth库
这是更推荐的方法,代码更简洁安全。
-
安装必要的库:
pip install Flask flask_httpauth -
创建Flask应用(
app.py):pythonfrom flask import Flask from flask_httpauth import HTTPBasicAuth from werkzeug.security import generate_password_hash, check_password_hash app = Flask(__name__) auth = HTTPBasicAuth() # 存储用户名和密码哈希值(密码是"hello") users = { "zhangsan": generate_password_hash("hello"), "lisi": generate_password_hash("bye") } @auth.verify_password def verify_password(username, password): """Flask-HTTPAuth 用于验证密码的回调函数""" if username in users and check_password_hash(users.get(username), password): return username # 返回非None值表示验证成功 @app.route('/') @auth.login_required # 此装饰器保护该路由,要求登录 def index(): return f"Hello, {auth.current_user()}! You are logged in." if __name__ == '__main__': app.run(debug=True, port=8000)运行后,访问
http://localhost:8000就会要求认证。
2.3 方案三:增强安全性(存储密码哈希)
绝对不要用明文存储密码。应使用werkzeug库的generate_password_hash和check_password_hash方法来处理。
python
from werkzeug.security import generate_password_hash, check_password_hash
# 在服务器启动前,预先为密码生成哈希值(只需做一次)
# 将生成的哈希值替换代码中的明文密码
hashed_password_1 = generate_password_hash('my_secure_password_1')
hashed_password_2 = generate_password_hash('my_secure_password_2')
print(f"用户1的密码哈希: {hashed_password_1}")
print(f"用户2的密码哈希: {hashed_password_2}")
# 在代码中,存储哈希值而非明文
users = {
"user1": hashed_password_1,
"user2": hashed_password_2
}
def verify_password(username, password):
if username in users:
# 检查输入的密码是否与存储的哈希值匹配
return check_password_hash(users[username], password)
return False
3. 重要安全提醒
-
务必使用HTTPS :Basic认证仅用Base64编码密码,相当于明文传输。在公网或生产环境使用,必须部署SSL/TLS证书(HTTPS),否则密码极易被窃听。
-
强密码策略:为认证账户设置强密码。
-
防火墙配置:确保服务器防火墙只开放必要的端口。
4. 总结
选择方案的建议:
-
快速实现且安全 :直接使用方案二(Flask + flask_httpauth) ,并结合方案三(密码哈希)。
-
深入学习原理 :尝试方案一(标准库手动实现)。