本文目录导读:

- 使用JWT (JSON Web Token) - 最推荐
- 使用
itsdangerous- Flask常用 - 使用
hashlib+ 随机数 - 简单实现 - Flask-JWT-Extended示例(完整Web应用)
- 安全建议
- 选择建议
我来介绍几种在Python中生成登录令牌的常见方法:
使用JWT (JSON Web Token) - 最推荐
安装依赖
pip install pyjwt
生成JWT令牌
import jwt
import datetime
from typing import Dict, Optional
# 密钥配置
SECRET_KEY = "your-secret-key-here"
ALGORITHM = "HS256"
def create_access_token(
data: Dict,
expires_delta: Optional[datetime.timedelta] = None
) -> str:
"""生成访问令牌"""
to_encode = data.copy()
if expires_delta:
expire = datetime.datetime.utcnow() + expires_delta
else:
# 默认24小时过期
expire = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
to_encode.update({"exp": expire})
token = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return token
def verify_token(token: str) -> Dict:
"""验证令牌"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise Exception("Token已过期")
except jwt.InvalidTokenError:
raise Exception("无效的Token")
# 使用示例
def login(username: str, password: str) -> str:
"""登录函数"""
# 这里应该是验证用户名和密码的逻辑
if username == "admin" and password == "123456":
token_data = {
"sub": username, # 用户标识
"user_id": 1,
"role": "admin"
}
token = create_access_token(
data=token_data,
expires_delta=datetime.timedelta(hours=2)
)
return token
else:
raise Exception("用户名或密码错误")
# 测试
if __name__ == "__main__":
# 登录
try:
token = login("admin", "123456")
print(f"生成的Token: {token}")
# 验证Token
payload = verify_token(token)
print(f"Token解析结果: {payload}")
except Exception as e:
print(f"错误: {e}")
使用 itsdangerous - Flask常用
安装
pip install itsdangerous
示例代码
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import BadSignature, SignatureExpired
class TokenManager:
def __init__(self, secret_key: str, expires_in: int = 3600):
"""
:param secret_key: 密钥
:param expires_in: 过期时间(秒)
"""
self.secret_key = secret_key
self.expires_in = expires_in
self.serializer = Serializer(
secret_key=secret_key,
expires_in=expires_in
)
def generate_token(self, user_data: dict) -> str:
"""生成令牌"""
return self.serializer.dumps(user_data).decode('utf-8')
def verify_token(self, token: str) -> dict:
"""验证令牌"""
try:
data = self.serializer.loads(token)
return data
except SignatureExpired:
raise Exception("Token已过期")
except BadSignature:
raise Exception("无效的Token")
# 使用示例
token_manager = TokenManager(
secret_key="my-secret-key",
expires_in=7200 # 2小时
)
# 生成Token
user_info = {"user_id": 123, "username": "john"}
token = token_manager.generate_token(user_info)
print(f"生成的Token: {token}")
# 验证Token
try:
data = token_manager.verify_token(token)
print(f"验证成功: {data}")
except Exception as e:
print(f"验证失败: {e}")
使用 hashlib + 随机数 - 简单实现
import hashlib
import random
import string
import time
import json
import base64
class SimpleToken:
def __init__(self, secret_key: str):
self.secret_key = secret_key
def generate_token(self, user_id: int, username: str) -> str:
"""生成简单令牌"""
# 创建payload
payload = {
"user_id": user_id,
"username": username,
"timestamp": int(time.time()),
"random": ''.join(random.choices(string.ascii_letters + string.digits, k=8))
}
# 将payload转为JSON并编码
payload_str = json.dumps(payload, sort_keys=True)
payload_b64 = base64.b64encode(payload_str.encode()).decode()
# 生成签名
signature = hashlib.sha256(
f"{payload_b64}{self.secret_key}".encode()
).hexdigest()
# 组合Token
token = f"{payload_b64}.{signature}"
return token
def verify_token(self, token: str) -> dict:
"""验证令牌"""
try:
payload_b64, signature = token.split('.')
# 验证签名
expected_signature = hashlib.sha256(
f"{payload_b64}{self.secret_key}".encode()
).hexdigest()
if signature != expected_signature:
raise Exception("Token签名无效")
# 解码payload
payload_str = base64.b64decode(payload_b64).decode()
payload = json.loads(payload_str)
# 检查过期时间(这里设置24小时过期)
current_time = int(time.time())
if current_time - payload['timestamp'] > 86400:
raise Exception("Token已过期")
return payload
except (ValueError, json.JSONDecodeError):
raise Exception("无效的Token格式")
# 使用示例
token_mgr = SimpleToken("my-secret-key")
# 生成Token
token = token_mgr.generate_token(1, "john_doe")
print(f"生成的Token: {token}")
# 验证Token
try:
data = token_mgr.verify_token(token)
print(f"验证成功: {data}")
except Exception as e:
print(f"验证失败: {e}")
Flask-JWT-Extended示例(完整Web应用)
from flask import Flask, request, jsonify
from flask_jwt_extended import (
JWTManager, create_access_token, jwt_required,
get_jwt_identity, create_refresh_token
)
from datetime import timedelta
app = Flask(__name__)
# 配置
app.config['JWT_SECRET_KEY'] = 'super-secret-key'
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=1)
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = timedelta(days=30)
jwt = JWTManager(app)
# 模拟用户数据
users = {
"admin": {"password": "123456", "role": "admin"},
"user": {"password": "password", "role": "user"}
}
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username')
password = request.json.get('password')
if not username or not password:
return jsonify({"msg": "需要用户名和密码"}), 400
user = users.get(username)
if not user or user['password'] != password:
return jsonify({"msg": "用户名或密码错误"}), 401
# 创建访问令牌和刷新令牌
access_token = create_access_token(
identity=username,
additional_claims={"role": user['role']}
)
refresh_token = create_refresh_token(identity=username)
return jsonify({
"access_token": access_token,
"refresh_token": refresh_token
}), 200
@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify({
"message": f"欢迎 {current_user}!",
"user": current_user
}), 200
@app.route('/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
current_user = get_jwt_identity()
new_token = create_access_token(identity=current_user)
return jsonify({"access_token": new_token}), 200
if __name__ == '__main__':
app.run(debug=True)
安全建议
- 使用HTTPS:始终在HTTPS下传输Token
- 设置合理的过期时间:避免Token长期有效
- 存储敏感信息:不要在Token中存储密码等敏感信息
- 密钥管理:保密JWT密钥,使用环境变量存储
- Token吊销:实现Token黑名单机制
选择建议
- 生产环境:推荐使用JWT (pyjwt)
- Flask应用:推荐Flask-JWT-Extended
- 简单需求:可以使用itsdangerous
- 学习目的:可以使用hashlib实现
这些方法各有优劣,根据你的具体需求选择合适的方案。