mirror of
https://github.com/insistence/RuoYi-Vue3-FastAPI.git
synced 2026-10-15 05:19:14 +00:00
* feat: 新增统一认证中心 * perf: 优化代码 * fix: 修复问题 * perf: 优化页面 * fix: 修复部分接口缺失Request参数的问题 * perf: 优化访问控制机制 * perf: 优化代码 * fix: 修复 Logout Token 缺少 exp * perf&fix: 优化和修复 * perf: 优化代码 * perf: 优化代码 * fix: 修复测试问题
236 lines
9.7 KiB
Python
236 lines
9.7 KiB
Python
from typing import Annotated
|
|
|
|
from fastapi import Path, Query, Request, Response
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from common.annotation.log_annotation import Log
|
|
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
|
|
from common.aspect.db_session import DBSessionDependency
|
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
|
from common.constant import ApiNamespace
|
|
from common.enums import BusinessType
|
|
from common.router import APIRouterPro
|
|
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
|
|
from exceptions.exception import ServiceException
|
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
|
from module_identity.entity.vo.oauth_session_vo import (
|
|
AccessPolicyModel,
|
|
AccessPolicyPageQueryModel,
|
|
GrantAccessModel,
|
|
GrantModel,
|
|
GrantPageQueryModel,
|
|
SessionPageQueryModel,
|
|
SessionRevokeModel,
|
|
SsoSessionModel,
|
|
)
|
|
from module_identity.service.oauth_session_management_service import OAuthSessionManagementService
|
|
from utils.oidc_util import OidcUtil
|
|
from utils.response_util import ResponseUtil
|
|
|
|
oauth_session_controller = APIRouterPro(
|
|
prefix='/system/oauth/session', order_num=22, tags=['系统管理-OAuth Session'], dependencies=[PreAuthDependency()]
|
|
)
|
|
oauth_grant_controller = APIRouterPro(
|
|
prefix='/system/oauth/grant', order_num=23, tags=['系统管理-OAuth Grant'], dependencies=[PreAuthDependency()]
|
|
)
|
|
_MAX_BATCH_SIZE = 100
|
|
|
|
|
|
def _actor(user: CurrentUserModel) -> str:
|
|
"""
|
|
提取管理操作者标识
|
|
|
|
:param user: 当前登录用户
|
|
:return: 安全截断后的用户名
|
|
:raises ServiceException: 当前用户不可用
|
|
"""
|
|
|
|
try:
|
|
return OidcUtil.actor_name(
|
|
getattr(getattr(user, 'user', None), 'user_name', None), error_message='当前操作者不可用'
|
|
)
|
|
except ValueError as exc:
|
|
raise ServiceException(message=str(exc)) from exc
|
|
|
|
|
|
@oauth_session_controller.get(
|
|
'/list',
|
|
summary='获取 OAuth 会话分页列表接口',
|
|
description='用于获取 OAuth 会话分页列表',
|
|
response_model=PageResponseModel[SsoSessionModel],
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthSession:list')],
|
|
)
|
|
async def list_oauth_sessions(
|
|
query: Annotated[SessionPageQueryModel, Query()], query_db: Annotated[AsyncSession, DBSessionDependency()]
|
|
) -> Response:
|
|
rows, total = await OAuthSessionManagementService.list_sessions(query_db, query)
|
|
|
|
return ResponseUtil.success(rows=rows, dict_content={'total': total})
|
|
|
|
|
|
@oauth_session_controller.delete(
|
|
'/user/{user_id}',
|
|
summary='撤销用户 OAuth 会话接口',
|
|
description='用于撤销指定用户的 OAuth 会话',
|
|
response_model=ResponseBaseModel,
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthSession:revoke')],
|
|
)
|
|
@ApiRateLimit(
|
|
namespace=ApiNamespace.SYSTEM_OAUTH_SESSION_USER_REVOKE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION
|
|
)
|
|
@Log(title='OAuth 会话管理', business_type=BusinessType.DELETE)
|
|
async def revoke_user_oauth_sessions(
|
|
request: Request,
|
|
user_id: Annotated[int, Path(gt=0)],
|
|
payload: SessionRevokeModel,
|
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
|
) -> Response:
|
|
count = await OAuthSessionManagementService.revoke_user(
|
|
query_db, request.app.state.redis, user_id, _actor(current_user), payload.reason
|
|
)
|
|
|
|
return ResponseUtil.success(msg='单点登录会话已撤销', data={'count': count})
|
|
|
|
|
|
@oauth_session_controller.get(
|
|
'/{sid}',
|
|
summary='查询 OAuth 会话详情接口',
|
|
description='用于查询 OAuth 会话详情',
|
|
response_model=DataResponseModel[SsoSessionModel],
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthSession:list')],
|
|
)
|
|
async def get_oauth_session(
|
|
sid: Annotated[str, Path(min_length=1, max_length=64)], query_db: Annotated[AsyncSession, DBSessionDependency()]
|
|
) -> Response:
|
|
data = await OAuthSessionManagementService.get_session(query_db, sid)
|
|
if data is None:
|
|
raise ServiceException(message='会话不存在')
|
|
return ResponseUtil.success(data=data)
|
|
|
|
|
|
@oauth_session_controller.delete(
|
|
'/{sids}',
|
|
summary='批量撤销 OAuth 会话接口',
|
|
description='用于批量撤销 OAuth 会话',
|
|
response_model=ResponseBaseModel,
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthSession:revoke')],
|
|
)
|
|
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_OAUTH_SESSION_REVOKE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
|
|
@Log(title='OAuth 会话管理', business_type=BusinessType.DELETE)
|
|
async def revoke_oauth_sessions(
|
|
request: Request,
|
|
sids: Annotated[str, Path(min_length=1, max_length=6500)],
|
|
payload: SessionRevokeModel,
|
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
|
) -> Response:
|
|
try:
|
|
batch_ids = OidcUtil.split_batch(sids, 'sids', max_size=_MAX_BATCH_SIZE, validate_all_first=True)
|
|
except ValueError as exc:
|
|
raise ServiceException(message=str(exc)) from exc
|
|
count = await OAuthSessionManagementService.revoke_sessions(
|
|
query_db, request.app.state.redis, batch_ids, _actor(current_user), payload.reason
|
|
)
|
|
|
|
return ResponseUtil.success(msg='单点登录会话已撤销', data={'count': count})
|
|
|
|
|
|
@oauth_grant_controller.get(
|
|
'/list',
|
|
summary='获取 OAuth 授权分页列表接口',
|
|
description='用于获取 OAuth 授权分页列表',
|
|
response_model=PageResponseModel[GrantModel],
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthGrant:list')],
|
|
)
|
|
async def list_oauth_grants(
|
|
query: Annotated[GrantPageQueryModel, Query()], query_db: Annotated[AsyncSession, DBSessionDependency()]
|
|
) -> Response:
|
|
rows, total = await OAuthSessionManagementService.list_grants(query_db, query)
|
|
|
|
return ResponseUtil.success(rows=rows, dict_content={'total': total})
|
|
|
|
|
|
@oauth_grant_controller.get(
|
|
'/access/list',
|
|
summary='获取用户应用访问策略分页列表接口',
|
|
description='用于查询独立访问策略,包含尚未授权过的用户与应用',
|
|
response_model=PageResponseModel[AccessPolicyModel],
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthGrant:list')],
|
|
)
|
|
async def list_oauth_access_policies(
|
|
query: Annotated[AccessPolicyPageQueryModel, Query()], query_db: Annotated[AsyncSession, DBSessionDependency()]
|
|
) -> Response:
|
|
rows, total = await OAuthSessionManagementService.list_access_policies(query_db, query)
|
|
|
|
return ResponseUtil.success(rows=rows, dict_content={'total': total})
|
|
|
|
|
|
@oauth_grant_controller.get(
|
|
'/{grant_id}',
|
|
summary='查询 OAuth 授权详情接口',
|
|
description='用于查询 OAuth 授权详情',
|
|
response_model=DataResponseModel[GrantModel],
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthGrant:list')],
|
|
)
|
|
async def get_oauth_grant(
|
|
grant_id: Annotated[str, Path(min_length=1, max_length=64)],
|
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
|
) -> Response:
|
|
data = await OAuthSessionManagementService.get_grant(query_db, grant_id)
|
|
if data is None:
|
|
raise ServiceException(message='授权记录不存在')
|
|
return ResponseUtil.success(data=data)
|
|
|
|
|
|
@oauth_grant_controller.delete(
|
|
'/{grant_ids}',
|
|
summary='批量撤销 OAuth 授权接口',
|
|
description='撤销选中记录所属用户对应用的全部现有授权,重新同意后可再次访问',
|
|
response_model=ResponseBaseModel,
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthGrant:revoke')],
|
|
)
|
|
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_OAUTH_GRANT_REVOKE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
|
|
@Log(title='OAuth 授权管理', business_type=BusinessType.DELETE)
|
|
async def revoke_oauth_grants(
|
|
request: Request,
|
|
grant_ids: Annotated[str, Path(min_length=1, max_length=6500)],
|
|
payload: SessionRevokeModel,
|
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
|
) -> Response:
|
|
try:
|
|
batch_ids = OidcUtil.split_batch(grant_ids, 'grant_ids', max_size=_MAX_BATCH_SIZE, validate_all_first=True)
|
|
except ValueError as exc:
|
|
raise ServiceException(message=str(exc)) from exc
|
|
count = await OAuthSessionManagementService.revoke_grants(query_db, batch_ids, _actor(current_user), payload.reason)
|
|
|
|
return ResponseUtil.success(msg='OAuth 授权已撤销', data={'count': count})
|
|
|
|
|
|
@oauth_grant_controller.put(
|
|
'/user/{user_id}/client/{client_id}/access',
|
|
summary='更新用户应用访问策略接口',
|
|
description='用于禁止用户访问应用或解除禁止,解除后仍需重新授权',
|
|
response_model=ResponseBaseModel,
|
|
dependencies=[UserInterfaceAuthDependency('system:oauthGrant:revoke')],
|
|
)
|
|
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_OAUTH_GRANT_ACCESS, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
|
|
@Log(title='OAuth 授权管理', business_type=BusinessType.UPDATE)
|
|
async def set_oauth_client_access(
|
|
request: Request,
|
|
user_id: Annotated[int, Path(gt=0)],
|
|
client_id: Annotated[str, Path(min_length=1, max_length=128)],
|
|
payload: GrantAccessModel,
|
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
|
) -> Response:
|
|
count = await OAuthSessionManagementService.set_access(
|
|
query_db, user_id, client_id, payload.blocked, _actor(current_user), payload.reason
|
|
)
|
|
return ResponseUtil.success(
|
|
msg='已禁止用户访问该应用' if payload.blocked else '已解除禁止,请重新授权',
|
|
data={'count': count, 'accessStatus': 'blocked' if payload.blocked else 'allowed'},
|
|
)
|