| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- """JWT 签发与严格校验。"""
- from __future__ import annotations
- from datetime import datetime, timedelta, timezone
- from uuid import uuid4
- import jwt
- from flask import current_app
- from dms.common.errors import AuthenticationError, InternalError, TokenExpiredError
- from dms.models import User
- ALGORITHM = "HS256"
- REQUIRED_CLAIMS = ("sub", "username", "roleCode", "authVersion", "iat", "exp", "jti", "iss")
- def _secret() -> str:
- secret = str(current_app.config.get("DMS_JWT_SECRET", "")).strip()
- if not secret:
- raise InternalError("JWT签名密钥未配置")
- return secret
- def issue_access_token(user: User, *, keep_signed_in: bool) -> tuple[str, int]:
- now = datetime.now(timezone.utc)
- duration_key = (
- "DMS_JWT_KEEP_SIGNED_IN_EXPIRES_SECONDS"
- if keep_signed_in
- else "DMS_JWT_EXPIRES_SECONDS"
- )
- expires_in = int(current_app.config[duration_key])
- claims = {
- "sub": str(user.id),
- "username": user.username,
- "roleCode": user.role_code,
- "authVersion": user.auth_version,
- "iat": now,
- "exp": now + timedelta(seconds=expires_in),
- "jti": str(uuid4()),
- "iss": current_app.config["DMS_JWT_ISSUER"],
- }
- return jwt.encode(claims, _secret(), algorithm=ALGORITHM), expires_in
- def decode_access_token(token: str) -> dict[str, object]:
- try:
- return jwt.decode(
- token,
- _secret(),
- algorithms=[ALGORITHM],
- issuer=current_app.config["DMS_JWT_ISSUER"],
- options={"require": list(REQUIRED_CLAIMS)},
- )
- except jwt.ExpiredSignatureError as exc:
- raise TokenExpiredError() from exc
- except jwt.PyJWTError as exc:
- raise AuthenticationError() from exc
|