first commit
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
"""
|
||||
认证服务 - 处理用户认证和 Token 管理
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from fastapi import Request
|
||||
from passlib.context import CryptContext
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from ..model.user import User
|
||||
from .user import UserService
|
||||
from ..core.jwt_cache import get_jwt_cache, TokenResponse, TokenData
|
||||
from ..core.config import get_config
|
||||
|
||||
|
||||
class AuthService:
|
||||
"""认证服务"""
|
||||
|
||||
def __init__(self):
|
||||
self.jwt_cache = get_jwt_cache()
|
||||
self.settings = get_config()
|
||||
self.pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
async def authenticate_user(
|
||||
self, email: str, password: str, session: AsyncSession
|
||||
) -> Optional[User]:
|
||||
"""验证用户凭据"""
|
||||
user = await UserService.get_user_by_email(email, session)
|
||||
if not user:
|
||||
return None
|
||||
if not self.pwd_context.verify(password, user.hashed_password):
|
||||
return None
|
||||
|
||||
return user
|
||||
|
||||
async def create_tokens(
|
||||
self,
|
||||
user: User,
|
||||
request: Optional[Request] = None,
|
||||
device_id: Optional[str] = None,
|
||||
) -> TokenResponse:
|
||||
"""为用户创建访问和刷新令牌"""
|
||||
|
||||
# 获取用户数据
|
||||
user_data = {
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"is_superuser": user.is_superuser,
|
||||
}
|
||||
|
||||
# 获取设备信息
|
||||
user_agent = None
|
||||
ip_address = None
|
||||
if request:
|
||||
user_agent = request.headers.get("user-agent")
|
||||
ip_address = request.client.host if request.client else None
|
||||
|
||||
# 创建访问令牌
|
||||
access_token = self.jwt_cache.create_token(
|
||||
user_id=str(user.id),
|
||||
user_data=user_data,
|
||||
token_type="access",
|
||||
device_id=device_id,
|
||||
user_agent=user_agent,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
|
||||
# 创建刷新令牌
|
||||
refresh_token = self.jwt_cache.create_token(
|
||||
user_id=str(user.id),
|
||||
user_data=user_data,
|
||||
token_type="refresh",
|
||||
device_id=device_id,
|
||||
user_agent=user_agent,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
|
||||
return TokenResponse(
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token,
|
||||
expires_in=self.settings["security"]["access_token_expire_minutes"] * 60,
|
||||
refresh_expires_in=getattr(self.settings, "refresh_token_expire_days", 7)
|
||||
* 24
|
||||
* 60
|
||||
* 60,
|
||||
)
|
||||
|
||||
async def validate_access_token(self, token: str) -> Optional[TokenData]:
|
||||
"""验证访问令牌"""
|
||||
validation = self.jwt_cache.validate_token(token, token_type="access")
|
||||
if not validation:
|
||||
return None
|
||||
|
||||
return TokenData(
|
||||
user_id=validation["user_id"],
|
||||
username=validation["payload"]["data"].get("username"),
|
||||
email=validation["payload"]["data"].get("email"),
|
||||
scopes=[], # 可以根据需要添加权限范围
|
||||
)
|
||||
|
||||
async def refresh_access_token(
|
||||
self,
|
||||
refresh_token: str,
|
||||
session: AsyncSession,
|
||||
request: Optional[Request] = None,
|
||||
) -> Optional[str]:
|
||||
"""使用刷新令牌获取新的访问令牌"""
|
||||
validation = self.jwt_cache.validate_token(refresh_token, token_type="access")
|
||||
if not validation:
|
||||
return None
|
||||
|
||||
user_id = validation["user_id"]
|
||||
|
||||
# 获取用户
|
||||
user = await UserService.get_user_by_id(int(user_id), session)
|
||||
if not user:
|
||||
return None
|
||||
|
||||
# 创建新的访问令牌
|
||||
user_data = {
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"is_superuser": user.is_superuser,
|
||||
}
|
||||
|
||||
device_id = validation.get("device_id")
|
||||
user_agent = None
|
||||
ip_address = None
|
||||
if request:
|
||||
user_agent = request.headers.get("user-agent")
|
||||
ip_address = request.client.host if request.client else None
|
||||
|
||||
new_access_token = self.jwt_cache.create_token(
|
||||
user_id=user_id,
|
||||
user_data=user_data,
|
||||
token_type="access",
|
||||
device_id=device_id,
|
||||
user_agent=user_agent,
|
||||
ip_address=ip_address,
|
||||
)
|
||||
|
||||
return new_access_token
|
||||
|
||||
async def logout(self, token: str):
|
||||
"""用户登出 - 使令牌失效"""
|
||||
self.jwt_cache.invalidate_token(token)
|
||||
|
||||
async def logout_all(self, user_id: str):
|
||||
"""使用户的所有令牌失效"""
|
||||
self.jwt_cache.invalidate_user_tokens(str(user_id))
|
||||
|
||||
async def get_user_sessions(self, user_id: str):
|
||||
"""获取用户的活跃会话"""
|
||||
return self.jwt_cache.get_user_sessions(str(user_id))
|
||||
|
||||
|
||||
# 全局认证服务实例
|
||||
_auth_service = None
|
||||
|
||||
|
||||
def get_auth_service() -> AuthService:
|
||||
"""获取认证服务实例(单例模式)"""
|
||||
global _auth_service
|
||||
if _auth_service is None:
|
||||
_auth_service = AuthService()
|
||||
return _auth_service
|
||||
Reference in New Issue
Block a user