diff --git a/backend/app/admin/service/auth_service.py b/backend/app/admin/service/auth_service.py index a8e38d52..115d055f 100644 --- a/backend/app/admin/service/auth_service.py +++ b/backend/app/admin/service/auth_service.py @@ -99,10 +99,11 @@ async def login( await redis_client.delete(f'{admin_settings.CAPTCHA_LOGIN_REDIS_PREFIX}:{request.state.ip}') await user_dao.update_login_time(db, obj.username) response.set_cookie( - settings.COOKIE_REFRESH_TOKEN_KEY, - refresh_token.refresh_token, - settings.COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS, - refresh_token.refresh_token_expire_time, + key=settings.COOKIE_REFRESH_TOKEN_KEY, + value=refresh_token.refresh_token, + max_age=settings.COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS, + expires=timezone.f_utc(refresh_token.refresh_token_expire_time), + httponly=True, ) await db.refresh(current_user) data = GetLoginToken( @@ -137,10 +138,11 @@ async def new_token(*, request: Request, response: Response) -> GetNewToken: multi_login=current_user.is_multi_login, ) response.set_cookie( - settings.COOKIE_REFRESH_TOKEN_KEY, - new_token.new_refresh_token, - settings.COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS, - new_token.new_refresh_token_expire_time, + key=settings.COOKIE_REFRESH_TOKEN_KEY, + value=new_token.new_refresh_token, + max_age=settings.COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS, + expires=timezone.f_utc(new_token.new_refresh_token_expire_time), + httponly=True, ) data = GetNewToken( access_token=new_token.new_access_token, diff --git a/backend/app/admin/service/oauth2_service.py b/backend/app/admin/service/oauth2_service.py index e2a6724d..55f84cc2 100644 --- a/backend/app/admin/service/oauth2_service.py +++ b/backend/app/admin/service/oauth2_service.py @@ -70,10 +70,11 @@ async def create_with_login( background_tasks.add_task(LoginLogService.create, **login_log) await redis_client.delete(f'{admin_settings.CAPTCHA_LOGIN_REDIS_PREFIX}:{request.state.ip}') response.set_cookie( - settings.COOKIE_REFRESH_TOKEN_KEY, - refresh_token.refresh_token, - settings.COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS, - refresh_token.refresh_token_expire_time, + key=settings.COOKIE_REFRESH_TOKEN_KEY, + value=refresh_token.refresh_token, + max_age=settings.COOKIE_REFRESH_TOKEN_EXPIRE_SECONDS, + expires=timezone.f_utc(refresh_token.refresh_token_expire_time), + httponly=True, ) data = GetLoginToken( access_token=access_token.access_token, diff --git a/backend/common/exception/exception_handler.py b/backend/common/exception/exception_handler.py index 97134431..b390817b 100644 --- a/backend/common/exception/exception_handler.py +++ b/backend/common/exception/exception_handler.py @@ -209,11 +209,12 @@ async def all_exception_handler(request: Request, exc: Exception): if settings.MIDDLEWARE_CORS: @app.exception_handler(StandardResponseCode.HTTP_500) - async def cors_status_code_500_exception_handler(request, exc): + async def cors_custom_code_500_exception_handler(request, exc): """ - 跨域 500 异常处理 + 跨域自定义 500 异常处理 `Related issue `_ + `Solution `_ :param request: :param exc: @@ -244,7 +245,7 @@ async def cors_status_code_500_exception_handler(request, exc): if origin: cors = CORSMiddleware( app=app, - allow_origins=['*'], + allow_origins=settings.CORS_ALLOWED_ORIGINS, allow_credentials=True, allow_methods=['*'], allow_headers=['*'], diff --git a/backend/core/conf.py b/backend/core/conf.py index de4b6059..50059bf2 100644 --- a/backend/core/conf.py +++ b/backend/core/conf.py @@ -86,7 +86,7 @@ def validate_openapi_url(cls, values): TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒 TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # refresh token 过期时间,单位:秒 TOKEN_REDIS_PREFIX: str = 'fba:token' - TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:token:refresh' + TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:refresh_token' TOKEN_EXCLUDE: list[str] = [ # JWT / RBAC 白名单 f'{API_V1_STR}/auth/login', ] @@ -109,6 +109,11 @@ def validate_openapi_url(cls, values): MIDDLEWARE_CORS: bool = True MIDDLEWARE_ACCESS: bool = True + # CORS + CORS_ALLOWED_ORIGINS: list[str] = [ + 'http://localhost:5173/', # 前端地址 + ] + # RBAC Permission PERMISSION_MODE: Literal['casbin', 'role-menu'] = 'casbin' PERMISSION_REDIS_PREFIX: str = 'fba:permission' diff --git a/backend/core/registrar.py b/backend/core/registrar.py index 63c2d104..6785406d 100644 --- a/backend/core/registrar.py +++ b/backend/core/registrar.py @@ -112,9 +112,9 @@ def register_middleware(app: FastAPI): :param app: :return: """ - # Opera log + # Opera log (required) app.add_middleware(OperaLogMiddleware) - # JWT auth, required + # JWT auth (required) app.add_middleware( AuthenticationMiddleware, backend=JwtAuthMiddleware(), on_error=JwtAuthMiddleware.auth_exception_handler ) @@ -129,7 +129,7 @@ def register_middleware(app: FastAPI): app.add_middleware( CORSMiddleware, - allow_origins=['*'], + allow_origins=settings.CORS_ALLOWED_ORIGINS, allow_credentials=True, allow_methods=['*'], allow_headers=['*'], diff --git a/backend/pyproject.toml b/backend/pyproject.toml index da7c6f4c..5f6beef7 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -32,7 +32,6 @@ dependencies = [ "pytest==7.2.2", "pytest-pretty==1.2.0", "python-jose==3.3.0", - "pytz==2023.3", "redis[hiredis]==5.0.1", "SQLAlchemy==2.0.30", "user-agents==2.2.0", diff --git a/backend/utils/timezone.py b/backend/utils/timezone.py index e9f37a96..9f6ff6f6 100644 --- a/backend/utils/timezone.py +++ b/backend/utils/timezone.py @@ -3,6 +3,7 @@ import zoneinfo from datetime import datetime +from datetime import timezone as datetime_timezone from backend.core.conf import settings @@ -38,5 +39,15 @@ def f_str(self, date_str: str, format_str: str = settings.DATETIME_FORMAT) -> da """ return datetime.strptime(date_str, format_str).replace(tzinfo=self.tz_info) + @staticmethod + def f_utc(dt: datetime) -> datetime: + """ + 时区时间转 UTC(GMT)时区 + + :param dt: + :return: + """ + return dt.astimezone(datetime_timezone.utc) + timezone = TimeZone()