Python HTTP服务器添加简单用户名密码认证的三种方案

目录

[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库

这是更推荐的方法,代码更简洁安全。

  1. 安装必要的库

    复制代码
    pip install Flask flask_httpauth
  2. 创建Flask应用(app.py

    python 复制代码
    from 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_hashcheck_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) ,并结合方案三(密码哈希)

  • 深入学习原理 :尝试方案一(标准库手动实现)

相关推荐
小鸡食米42 分钟前
Nginx基础
运维·服务器·nginx
Albert Edison5 小时前
【Python】学生管理系统
开发语言·数据库·python
love530love7 小时前
【ComfyUI】解决 ModuleNotFoundError: No module named ‘inference_core_nodes‘ 问题
人工智能·windows·python·comfyui·inference-core
2501_907136828 小时前
手搓仓库管理系统Senbar-1.0.4(附带财务管理板块)
运维·服务器·软件需求
badwomen__8 小时前
MOV 指令的数据流向
服务器·性能优化
亚亚的学习和分享8 小时前
python基础语法----条件语句
python
盟接之桥9 小时前
盟接之桥EDI软件:API数据采集模块深度解析,打造企业数据协同新引擎
java·运维·服务器·网络·数据库·人工智能·制造
2501_907136829 小时前
离线工具箱 内含53个小工具
linux·服务器·网络
Zzz 小生9 小时前
LangChain Streaming-Overview:流式处理使用完全指南
人工智能·python·语言模型·langchain·github
yzx99101310 小时前
Python数据结构入门指南:从基础到实践
开发语言·数据结构·python