add
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
"""安全组件:bcrypt 密码哈希 + JWT 双 Token(对齐《02-技术文档》4.2)"""
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import bcrypt
|
||||
import jwt
|
||||
|
||||
from app.config import settings
|
||||
from app.core import errors
|
||||
from app.core.response import BizException
|
||||
|
||||
|
||||
def hash_password(plain: str) -> str:
|
||||
return bcrypt.hashpw(plain.encode(), bcrypt.gensalt()).decode()
|
||||
|
||||
|
||||
def verify_password(plain: str, hashed: str) -> bool:
|
||||
try:
|
||||
return bcrypt.checkpw(plain.encode(), hashed.encode())
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def _create_token(subject: int, token_type: str, ttl: int, epoch: int = 0) -> tuple[str, str, int]:
|
||||
"""生成 JWT,返回 (token, jti, 过期时间戳)"""
|
||||
now = datetime.now(timezone.utc)
|
||||
jti = uuid.uuid4().hex
|
||||
exp = now + timedelta(seconds=ttl)
|
||||
payload = {
|
||||
"sub": str(subject),
|
||||
"jti": jti,
|
||||
"type": token_type, # access / refresh / admin:{role}
|
||||
"ep": epoch, # 令牌纪元:改密/注销后递增使旧 Token 全端失效
|
||||
"iat": int(now.timestamp()),
|
||||
"exp": exp,
|
||||
}
|
||||
token = jwt.encode(payload, settings.jwt_secret, algorithm=settings.jwt_algorithm)
|
||||
return token, jti, int(exp.timestamp())
|
||||
|
||||
|
||||
def create_access_token(user_id: int, epoch: int = 0) -> tuple[str, str, int]:
|
||||
return _create_token(user_id, "access", settings.access_token_ttl, epoch)
|
||||
|
||||
|
||||
def create_refresh_token(user_id: int, epoch: int = 0) -> tuple[str, str, int]:
|
||||
return _create_token(user_id, "refresh", settings.refresh_token_ttl, epoch)
|
||||
|
||||
|
||||
def create_admin_token(admin_id: int, role: str) -> tuple[str, str, int]:
|
||||
"""管理员 Token,payload 带角色,有效期 12h"""
|
||||
token, jti, exp = _create_token(admin_id, f"admin:{role}", settings.admin_token_ttl)
|
||||
return token, jti, exp
|
||||
|
||||
|
||||
def decode_token(token: str) -> dict:
|
||||
"""解码并校验 Token,失败抛 1002"""
|
||||
try:
|
||||
payload = jwt.decode(token, settings.jwt_secret, algorithms=[settings.jwt_algorithm])
|
||||
except jwt.PyJWTError:
|
||||
raise BizException(errors.UNAUTHORIZED, http_status=401)
|
||||
return payload
|
||||
Reference in New Issue
Block a user