From 7d1deab48bf9e4285d5ef59559cd7d05c4a5d8e8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 May 2022 21:56:28 +0800 Subject: [PATCH] 调整包结构,oauth2 独立 --- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApiImpl.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.http | 23 ----------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.java | 74 -------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java | 146 -------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java | 50 -------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java | 31 +++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java | 46 ++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java | 33 +++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialBindLoginReqVO.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java | 35 +++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginReqVO.java | 45 --------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginRespVO.java | 31 ------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthMenuRespVO.java | 48 ------------------------------------------------ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthPermissionInfoRespVO.java | 46 ---------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsLoginReqVO.java | 38 -------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsSendReqVO.java | 33 --------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialBindLoginReqVO.java | 48 ------------------------------------------------ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialQuickLoginReqVO.java | 35 ----------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java | 82 ---------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientCreateReqVO.java | 12 ------------ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientPageReqVO.java | 19 ------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientRespVO.java | 23 ----------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientUpdateReqVO.java | 21 --------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java | 23 ----------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java | 41 ----------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http | 23 +++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.java | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientBaseVO.java | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientCreateReqVO.java | 12 ++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java | 19 +++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java | 23 +++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientUpdateReqVO.java | 21 +++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java | 23 +++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java | 41 +++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2ClientConvert.java | 6 +++--- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2ClientMapper.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java | 3 ++- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminOAuth2Service.java | 28 ---------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveService.java | 27 --------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveServiceImpl.java | 20 -------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientService.java | 87 --------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImpl.java | 203 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2CodeService.java | 14 -------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenService.java | 77 ----------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenServiceImpl.java | 163 ------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java | 39 +++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java | 26 ++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java | 14 ++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java | 30 ++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java | 29 +++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java | 5 +++-- yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java | 7 ++++--- 67 files changed, 1539 insertions(+), 1474 deletions(-) delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.http delete mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialBindLoginReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginRespVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthMenuRespVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthPermissionInfoRespVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsLoginReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsSendReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialBindLoginReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialQuickLoginReqVO.java delete mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java delete mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientCreateReqVO.java delete mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientPageReqVO.java delete mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientRespVO.java delete mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientUpdateReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http create mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java create mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientBaseVO.java create mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientCreateReqVO.java create mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java create mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java create mode 100755 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientUpdateReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminOAuth2Service.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2CodeService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApiImpl.java index d9e873c..3c2c291 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApiImpl.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; -import cn.iocoder.yudao.module.system.service.auth.OAuth2TokenService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import org.springframework.stereotype.Service; import javax.annotation.Resource; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index 3d38175..e42a5df 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.framework.security.config.SecurityProperties; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.http deleted file mode 100644 index dcf60a6..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.http +++ /dev/null @@ -1,23 +0,0 @@ -### 请求 /login 接口 => 成功 -POST {{baseUrl}}/system/oauth2-client/create -Content-Type: application/json -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} - -{ - "id": "1", - "secret": "admin123", - "name": "芋道源码", - "logo": "https://www.iocoder.cn/images/favicon.ico", - "description": "我是描述", - "status": 0, - "accessTokenValiditySeconds": 180, - "refreshTokenValiditySeconds": 8640, - "redirectUris": ["https://www.iocoder.cn"], - "autoApprove": true, - "authorizedGrantTypes": ["password"], - "scopes": ["user_info"], - "authorities": ["system:user:query"], - "resource_ids": ["1024"], - "additionalInformation": "{}" -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.java deleted file mode 100755 index 2912957..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2ClientController.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientRespVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientUpdateReqVO; -import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; -import cn.iocoder.yudao.module.system.service.auth.OAuth2ClientService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiOperation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Api(tags = "管理后台 - OAuth2 客户端") -@RestController -@RequestMapping("/system/oauth2-client") -@Validated -public class OAuth2ClientController { - - @Resource - private OAuth2ClientService oAuth2ClientService; - - @PostMapping("/create") - @ApiOperation("创建 OAuth2 客户端") - @PreAuthorize("@ss.hasPermission('system:oauth2-client:create')") - public CommonResult createOAuth2Client(@Valid @RequestBody OAuth2ClientCreateReqVO createReqVO) { - return success(oAuth2ClientService.createOAuth2Client(createReqVO)); - } - - @PutMapping("/update") - @ApiOperation("更新 OAuth2 客户端") - @PreAuthorize("@ss.hasPermission('system:oauth2-client:update')") - public CommonResult updateOAuth2Client(@Valid @RequestBody OAuth2ClientUpdateReqVO updateReqVO) { - oAuth2ClientService.updateOAuth2Client(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @ApiOperation("删除 OAuth2 客户端") - @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) - @PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')") - public CommonResult deleteOAuth2Client(@RequestParam("id") Long id) { - oAuth2ClientService.deleteOAuth2Client(id); - return success(true); - } - - @GetMapping("/get") - @ApiOperation("获得 OAuth2 客户端") - @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) - @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") - public CommonResult getOAuth2Client(@RequestParam("id") Long id) { - OAuth2ClientDO oAuth2Client = oAuth2ClientService.getOAuth2Client(id); - return success(OAuth2ClientConvert.INSTANCE.convert(oAuth2Client)); - } - - @GetMapping("/page") - @ApiOperation("获得OAuth2 客户端分页") - @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") - public CommonResult> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) { - PageResult pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO); - return success(OAuth2ClientConvert.INSTANCE.convertPage(pageResult)); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java deleted file mode 100644 index 772221d..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java +++ /dev/null @@ -1,146 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; -import cn.iocoder.yudao.module.system.service.auth.OAuth2ApproveService; -import cn.iocoder.yudao.module.system.service.auth.OAuth2ClientService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import lombok.extern.slf4j.Slf4j; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -@Api(tags = "管理后台 - OAuth2.0 授权") -@RestController -@RequestMapping("/system/oauth2") -@Validated -@Slf4j -public class OAuth2Controller { - -// POST oauth/token TokenEndpoint:Password、Implicit、Code、Refresh Token - -// POST oauth/check_token CheckTokenEndpoint - -// DELETE oauth/token ConsumerTokenServices#revokeToken - -// GET oauth/authorize AuthorizationEndpoint - - @Resource - private OAuth2ClientService oauth2ClientService; - @Resource - private OAuth2ApproveService oauth2ApproveService; - - @GetMapping("/authorize") - @ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用") - @ApiImplicitParams({ - @ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class), - @ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class), - @ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 多个使用空格分隔 - @ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class), - @ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class) - }) - // 情况一:满足自动授权,则走类似 approveOrDeny 的逻辑,最终返回是 CommonResult - // 情况二:如果不满足自动授权,则返回授权相关的展示信息,最终返回是 CommonResult - public CommonResult authorize(@RequestParam("response_type") String responseType, - @RequestParam("client_id") String clientId, - @RequestParam(value = "scope", required = false) String scope, - @RequestParam("redirect_uri") String redirectUri, - @RequestParam(value = "state", required = false) String state) { - List scopes = StrUtil.split(scope, ' '); - // 0. 校验用户已经登录。通过 Spring Security 实现 - - // 1.1 校验 responseType 是否满足 code 或者 token 值 - OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType); - // 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内 - oauth2ClientService.validOAuthClientFromCache(clientId, grantTypeEnum.getGrantType(), scopes, redirectUri); - - // 2. 判断是否满足自动授权(满足) - boolean approved = oauth2ApproveService.checkForPreApproval(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes); - if (approved) { - // 2.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 - if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { - return success(getAuthorizationCodeRedirect()); - } - return success(getImplicitGrantRedirect()); - } - - // 3. 不满足自动授权,则返回授权相关的展示信息 - return null; - } - - @PostMapping("/authorize") - @ApiOperation(value = "申请授权", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【提交】调用") - @ApiImplicitParams({ - @ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class), - @ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class), - @ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 使用 Map 格式,Spring MVC 暂时不支持这么接收参数 - @ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class), - @ApiImplicitParam(name = "approved", value = "用户是否接受", example = "true", dataTypeClass = Boolean.class), // 该参数为 null 时,会基于用户是否已经授权过,进行自动判断 - @ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class) - }) - @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - // 因为前后端分离,Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL,剩余交给前端处理 - public CommonResult approveOrDeny(@RequestParam("response_type") String responseType, - @RequestParam("client_id") String clientId, - @RequestParam(value = "scope", required = false) String scope, - @RequestParam("redirect_uri") String redirectUri, - @RequestParam("approved") Boolean approved, - @RequestParam(value = "state", required = false) String state) { - @SuppressWarnings("unchecked") - Map scopes = JsonUtils.parseObject(scope, Map.class); - scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap()); - // TODO 芋艿:针对 approved + scopes 在看看 spring security 的实现 - // 0. 校验用户已经登录。通过 Spring Security 实现 - - // 1.1 校验 responseType 是否满足 code 或者 token 值 - OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType); - // 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内 - oauth2ClientService.validOAuthClientFromCache(clientId, grantTypeEnum.getGrantType(), scopes.keySet(), redirectUri); - - // 2.1 - // 2.2 - - // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 - if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { - return success(getAuthorizationCodeRedirect()); - } - // 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向 - return success(getImplicitGrantRedirect()); - } - - private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) { - if (StrUtil.equals(responseType, "code")) { - return OAuth2GrantTypeEnum.AUTHORIZATION_CODE; - } - if (StrUtil.equalsAny(responseType, "token")) { - return OAuth2GrantTypeEnum.IMPLICIT; - } - throw exception0(BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token"); - } - - private String getImplicitGrantRedirect() { - return ""; - } - - private String getAuthorizationCodeRedirect() { - return ""; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java deleted file mode 100644 index 042a873..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenRespVO; -import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; -import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; -import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; -import cn.iocoder.yudao.module.system.service.auth.OAuth2TokenService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiOperation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Api(tags = "管理后台 - OAuth2.0 令牌") -@RestController -@RequestMapping("/system/oauth2-token") -public class OAuth2TokenController { - - @Resource - private OAuth2TokenService oauth2TokenService; - @Resource - private AdminAuthService authService; - - @GetMapping("/page") - @ApiOperation(value = "获得访问令牌分页", notes = "只返回有效期内的") - @PreAuthorize("@ss.hasPermission('system:oauth2-token:page')") - public CommonResult> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) { - PageResult pageResult = oauth2TokenService.getAccessTokenPage(reqVO); - return success(OAuth2TokenConvert.INSTANCE.convert(pageResult)); - } - - @DeleteMapping("/delete") - @ApiOperation("删除访问令牌") - @ApiImplicitParam(name = "accessToken", value = "访问令牌", required = true, dataTypeClass = String.class, example = "tudou") - @PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')") - public CommonResult deleteAccessToken(@RequestParam("accessToken") String accessToken) { - authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType()); - return success(true); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java new file mode 100644 index 0000000..0ecd3d6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@ApiModel("管理后台 - 账号密码登录 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthLoginReqVO { + + @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") + @NotEmpty(message = "登录账号不能为空") + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + private String username; + + @ApiModelProperty(value = "密码", required = true, example = "buzhidao") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") + @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) + private String code; + + @ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62", notes = "验证码开启时,需要传递") + @NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class) + private String uuid; + + /** + * 开启验证码的 Group + */ + public interface CodeEnableGroup {} + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java new file mode 100644 index 0000000..ec83a69 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@ApiModel("管理后台 - 登录 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthLoginRespVO { + + @ApiModelProperty(value = "用户编号", required = true, example = "1024") + private Long userId; + + @ApiModelProperty(value = "访问令牌", required = true, example = "happy") + private String accessToken; + + @ApiModelProperty(value = "刷新令牌", required = true, example = "nice") + private String refreshToken; + + @ApiModelProperty(value = "过期时间", required = true) + private Date expiresTime; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java new file mode 100644 index 0000000..2ae7eaa --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@ApiModel("管理后台 - 登录用户的菜单信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthMenuRespVO { + + @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") + private Long id; + + @ApiModelProperty(value = "父菜单 ID", required = true, example = "1024") + private Long parentId; + + @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "路由地址", example = "post", notes = "仅菜单类型为菜单或者目录时,才需要传") + private String path; + + @ApiModelProperty(value = "组件路径", example = "system/post/index", notes = "仅菜单类型为菜单时,才需要传") + private String component; + + @ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传") + private String icon; + + @ApiModelProperty(value = "是否可见", required = true, example = "false") + private Boolean visible; + + @ApiModelProperty(value = "是否缓存", required = true, example = "false") + private Boolean keepAlive; + + /** + * 子路由 + */ + private List children; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java new file mode 100644 index 0000000..0e80922 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Set; + +@ApiModel(value = "管理后台 - 登录用户的权限信息 Response VO", description = "额外包括用户信息和角色列表") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthPermissionInfoRespVO { + + @ApiModelProperty(value = "用户信息", required = true) + private UserVO user; + + @ApiModelProperty(value = "角色标识数组", required = true) + private Set roles; + + @ApiModelProperty(value = "操作权限数组", required = true) + private Set permissions; + + @ApiModel("用户信息 VO") + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class UserVO { + + @ApiModelProperty(value = "用户编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "用户昵称", required = true, example = "芋道源码") + private String nickname; + + @ApiModelProperty(value = "用户头像", required = true, example = "http://www.iocoder.cn/xx.jpg") + private String avatar; + + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java new file mode 100644 index 0000000..5e41355 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@ApiModel("管理后台 - 短信验证码的呢老姑 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSmsLoginReqVO { + + @ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma") + @NotEmpty(message = "手机号不能为空") + @Length(min = 11, max = 11, message = "手机号格式错误,仅支持大陆手机号") + @Pattern(regexp = "^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$", message = "账号格式为数字以及字母") + private String mobile; + + + + @ApiModelProperty(value = "短信验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") + @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) + private String code; + + /** + * 开启验证码的 Group + */ + public interface CodeEnableGroup {} + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java new file mode 100644 index 0000000..0df9a52 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 发送手机验证码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSmsSendReqVO { + + @ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @ApiModelProperty(value = "短信场景", required = true, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialBindLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialBindLoginReqVO.java new file mode 100644 index 0000000..cefe40d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialBindLoginReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +@ApiModel("管理后台 - 社交绑定登录 Request VO,使用 code 授权码 + 账号密码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSocialBindLoginReqVO { + + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @ApiModelProperty(value = "授权码", required = true, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + + @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") + @NotEmpty(message = "登录账号不能为空") + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + private String username; + + @ApiModelProperty(value = "密码", required = true, example = "buzhidao") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java new file mode 100644 index 0000000..4b7ebb1 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 社交快捷登录 Request VO,使用 code 授权码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSocialQuickLoginReqVO { + + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @ApiModelProperty(value = "授权码", required = true, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginReqVO.java deleted file mode 100644 index 013c0b2..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginReqVO.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Pattern; - -@ApiModel("管理后台 - 账号密码登录 Request VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthLoginReqVO { - - @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") - @NotEmpty(message = "登录账号不能为空") - @Length(min = 4, max = 16, message = "账号长度为 4-16 位") - @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") - private String username; - - @ApiModelProperty(value = "密码", required = true, example = "buzhidao") - @NotEmpty(message = "密码不能为空") - @Length(min = 4, max = 16, message = "密码长度为 4-16 位") - private String password; - - @ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") - @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) - private String code; - - @ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62", notes = "验证码开启时,需要传递") - @NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class) - private String uuid; - - /** - * 开启验证码的 Group - */ - public interface CodeEnableGroup {} - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginRespVO.java deleted file mode 100644 index 915a550..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthLoginRespVO.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.Date; - -@ApiModel("管理后台 - 登录 Response VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthLoginRespVO { - - @ApiModelProperty(value = "用户编号", required = true, example = "1024") - private Long userId; - - @ApiModelProperty(value = "访问令牌", required = true, example = "happy") - private String accessToken; - - @ApiModelProperty(value = "刷新令牌", required = true, example = "nice") - private String refreshToken; - - @ApiModelProperty(value = "过期时间", required = true) - private Date expiresTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthMenuRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthMenuRespVO.java deleted file mode 100644 index 74e8c74..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthMenuRespVO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@ApiModel("管理后台 - 登录用户的菜单信息 Response VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthMenuRespVO { - - @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") - private Long id; - - @ApiModelProperty(value = "父菜单 ID", required = true, example = "1024") - private Long parentId; - - @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") - private String name; - - @ApiModelProperty(value = "路由地址", example = "post", notes = "仅菜单类型为菜单或者目录时,才需要传") - private String path; - - @ApiModelProperty(value = "组件路径", example = "system/post/index", notes = "仅菜单类型为菜单时,才需要传") - private String component; - - @ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传") - private String icon; - - @ApiModelProperty(value = "是否可见", required = true, example = "false") - private Boolean visible; - - @ApiModelProperty(value = "是否缓存", required = true, example = "false") - private Boolean keepAlive; - - /** - * 子路由 - */ - private List children; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthPermissionInfoRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthPermissionInfoRespVO.java deleted file mode 100644 index bada252..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthPermissionInfoRespVO.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.Set; - -@ApiModel(value = "管理后台 - 登录用户的权限信息 Response VO", description = "额外包括用户信息和角色列表") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthPermissionInfoRespVO { - - @ApiModelProperty(value = "用户信息", required = true) - private UserVO user; - - @ApiModelProperty(value = "角色标识数组", required = true) - private Set roles; - - @ApiModelProperty(value = "操作权限数组", required = true) - private Set permissions; - - @ApiModel("用户信息 VO") - @Data - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class UserVO { - - @ApiModelProperty(value = "用户编号", required = true, example = "1024") - private Long id; - - @ApiModelProperty(value = "用户昵称", required = true, example = "芋道源码") - private String nickname; - - @ApiModelProperty(value = "用户头像", required = true, example = "http://www.iocoder.cn/xx.jpg") - private String avatar; - - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsLoginReqVO.java deleted file mode 100644 index 4360b98..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsLoginReqVO.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Pattern; - -@ApiModel("管理后台 - 短信验证码的呢老姑 Request VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthSmsLoginReqVO { - - @ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma") - @NotEmpty(message = "手机号不能为空") - @Length(min = 11, max = 11, message = "手机号格式错误,仅支持大陆手机号") - @Pattern(regexp = "^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$", message = "账号格式为数字以及字母") - private String mobile; - - - - @ApiModelProperty(value = "短信验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") - @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) - private String code; - - /** - * 开启验证码的 Group - */ - public interface CodeEnableGroup {} - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsSendReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsSendReqVO.java deleted file mode 100644 index adcd048..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSmsSendReqVO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -@ApiModel("管理后台 - 发送手机验证码 Request VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthSmsSendReqVO { - - @ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma") - @NotEmpty(message = "手机号不能为空") - @Mobile - private String mobile; - - @ApiModelProperty(value = "短信场景", required = true, example = "1") - @NotNull(message = "发送场景不能为空") - @InEnum(SmsSceneEnum.class) - private Integer scene; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialBindLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialBindLoginReqVO.java deleted file mode 100644 index 71f5cfe..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialBindLoginReqVO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; - -@ApiModel("管理后台 - 社交绑定登录 Request VO,使用 code 授权码 + 账号密码") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthSocialBindLoginReqVO { - - @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值") - @InEnum(SocialTypeEnum.class) - @NotNull(message = "社交平台的类型不能为空") - private Integer type; - - @ApiModelProperty(value = "授权码", required = true, example = "1024") - @NotEmpty(message = "授权码不能为空") - private String code; - - @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") - @NotEmpty(message = "state 不能为空") - private String state; - - @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") - @NotEmpty(message = "登录账号不能为空") - @Length(min = 4, max = 16, message = "账号长度为 4-16 位") - @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") - private String username; - - @ApiModelProperty(value = "密码", required = true, example = "buzhidao") - @NotEmpty(message = "密码不能为空") - @Length(min = 4, max = 16, message = "密码长度为 4-16 位") - private String password; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialQuickLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialQuickLoginReqVO.java deleted file mode 100644 index 2bec436..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/auth/AuthSocialQuickLoginReqVO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth; - -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -@ApiModel("管理后台 - 社交快捷登录 Request VO,使用 code 授权码") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AuthSocialQuickLoginReqVO { - - @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值") - @InEnum(SocialTypeEnum.class) - @NotNull(message = "社交平台的类型不能为空") - private Integer type; - - @ApiModelProperty(value = "授权码", required = true, example = "1024") - @NotEmpty(message = "授权码不能为空") - private String code; - - @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") - @NotEmpty(message = "state 不能为空") - private String state; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java deleted file mode 100755 index 4c13263..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java +++ /dev/null @@ -1,82 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.client; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.hibernate.validator.constraints.URL; - -import javax.validation.constraints.AssertTrue; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -/** -* OAuth2 客户端 Base VO,提供给添加、修改、详细的子 VO 使用 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 -*/ -@Data -public class OAuth2ClientBaseVO { - - @ApiModelProperty(value = "客户端编号", required = true) - @NotNull(message = "客户端编号不能为空") - private String clientId; - - @ApiModelProperty(value = "客户端密钥", required = true) - @NotNull(message = "客户端密钥不能为空") - private String secret; - - @ApiModelProperty(value = "应用名", required = true) - @NotNull(message = "应用名不能为空") - private String name; - - @ApiModelProperty(value = "应用图标", required = true) - @NotNull(message = "应用图标不能为空") - @URL(message = "应用图标的地址不正确") - private String logo; - - @ApiModelProperty(value = "应用描述") - private String description; - - @ApiModelProperty(value = "状态", required = true) - @NotNull(message = "状态不能为空") - private Integer status; - - @ApiModelProperty(value = "访问令牌的有效期", required = true) - @NotNull(message = "访问令牌的有效期不能为空") - private Integer accessTokenValiditySeconds; - - @ApiModelProperty(value = "刷新令牌的有效期", required = true) - @NotNull(message = "刷新令牌的有效期不能为空") - private Integer refreshTokenValiditySeconds; - - @ApiModelProperty(value = "可重定向的 URI 地址", required = true) - @NotNull(message = "可重定向的 URI 地址不能为空") - private List<@NotEmpty(message = "重定向的 URI 不能为空") - @URL(message = "重定向的 URI 格式不正确") String> redirectUris; - - @ApiModelProperty(value = "授权类型", required = true, example = "password", notes = "参见 OAuth2GrantTypeEnum 枚举") - @NotNull(message = "授权类型不能为空") - private List authorizedGrantTypes; - - @ApiModelProperty(value = "授权范围", example = "user_info") - private List scopes; - - @ApiModelProperty(value = "自动通过的授权范围", example = "user_info") - private List autoApproveScopes; - - @ApiModelProperty(value = "权限", example = "system:user:query") - private List authorities; - - @ApiModelProperty(value = "资源", example = "1024") - private List resourceIds; - - @ApiModelProperty(value = "附加信息", example = "{yunai: true}") - private String additionalInformation; - - @AssertTrue(message = "附加信息必须是 JSON 格式") - public boolean isAdditionalInformationJson() { - return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientCreateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientCreateReqVO.java deleted file mode 100755 index f49735e..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientCreateReqVO.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.client; - -import lombok.*; -import io.swagger.annotations.*; - -@ApiModel("管理后台 - OAuth2 客户端创建 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class OAuth2ClientCreateReqVO extends OAuth2ClientBaseVO { - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientPageReqVO.java deleted file mode 100755 index aa6434a..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientPageReqVO.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.client; - -import lombok.*; -import io.swagger.annotations.*; -import cn.iocoder.yudao.framework.common.pojo.PageParam; - -@ApiModel("管理后台 - OAuth2 客户端分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class OAuth2ClientPageReqVO extends PageParam { - - @ApiModelProperty(value = "应用名") - private String name; - - @ApiModelProperty(value = "状态") - private Integer status; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientRespVO.java deleted file mode 100755 index 6416d74..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientRespVO.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.client; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.util.Date; - -@ApiModel("管理后台 - OAuth2 客户端 Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class OAuth2ClientRespVO extends OAuth2ClientBaseVO { - - @ApiModelProperty(value = "编号", required = true) - private Long id; - - @ApiModelProperty(value = "创建时间", required = true) - private Date createTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientUpdateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientUpdateReqVO.java deleted file mode 100755 index 2747905..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientUpdateReqVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.client; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import javax.validation.constraints.NotNull; - -@ApiModel("管理后台 - OAuth2 客户端更新 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class OAuth2ClientUpdateReqVO extends OAuth2ClientBaseVO { - - @ApiModelProperty(value = "编号", required = true) - @NotNull(message = "编号不能为空") - private Long id; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java deleted file mode 100644 index 41dff4a..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.token; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@ApiModel("管理后台 - 访问令牌分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -public class OAuth2AccessTokenPageReqVO extends PageParam { - - @ApiModelProperty(value = "用户编号", required = true, example = "666") - private Long userId; - - @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") - private Integer userType; - - @ApiModelProperty(value = "客户端编号", required = true, example = "2") - private String clientId; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java deleted file mode 100644 index 678a215..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.auth.vo.token; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.Date; - -@ApiModel("管理后台 - 访问令牌 Response VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -public class OAuth2AccessTokenRespVO { - - @ApiModelProperty(value = "编号", required = true, example = "1024") - private Long id; - - @ApiModelProperty(value = "访问令牌", required = true, example = "tudou") - private String accessToken; - - @ApiModelProperty(value = "刷新令牌", required = true, example = "nice") - private String refreshToken; - - @ApiModelProperty(value = "用户编号", required = true, example = "666") - private Long userId; - - @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") - private Integer userType; - - @ApiModelProperty(value = "客户端编号", required = true, example = "2") - private String clientId; - - @ApiModelProperty(value = "创建时间", required = true) - private Date createTime; - - @ApiModelProperty(value = "过期时间", required = true) - private Date expiresTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http new file mode 100644 index 0000000..dcf60a6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http @@ -0,0 +1,23 @@ +### 请求 /login 接口 => 成功 +POST {{baseUrl}}/system/oauth2-client/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "id": "1", + "secret": "admin123", + "name": "芋道源码", + "logo": "https://www.iocoder.cn/images/favicon.ico", + "description": "我是描述", + "status": 0, + "accessTokenValiditySeconds": 180, + "refreshTokenValiditySeconds": 8640, + "redirectUris": ["https://www.iocoder.cn"], + "autoApprove": true, + "authorizedGrantTypes": ["password"], + "scopes": ["user_info"], + "authorities": ["system:user:query"], + "resource_ids": ["1024"], + "additionalInformation": "{}" +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java new file mode 100755 index 0000000..0e5b109 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; +import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - OAuth2 客户端") +@RestController +@RequestMapping("/system/oauth2-client") +@Validated +public class OAuth2ClientController { + + @Resource + private OAuth2ClientService oAuth2ClientService; + + @PostMapping("/create") + @ApiOperation("创建 OAuth2 客户端") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:create')") + public CommonResult createOAuth2Client(@Valid @RequestBody OAuth2ClientCreateReqVO createReqVO) { + return success(oAuth2ClientService.createOAuth2Client(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新 OAuth2 客户端") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:update')") + public CommonResult updateOAuth2Client(@Valid @RequestBody OAuth2ClientUpdateReqVO updateReqVO) { + oAuth2ClientService.updateOAuth2Client(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除 OAuth2 客户端") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')") + public CommonResult deleteOAuth2Client(@RequestParam("id") Long id) { + oAuth2ClientService.deleteOAuth2Client(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得 OAuth2 客户端") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") + public CommonResult getOAuth2Client(@RequestParam("id") Long id) { + OAuth2ClientDO oAuth2Client = oAuth2ClientService.getOAuth2Client(id); + return success(OAuth2ClientConvert.INSTANCE.convert(oAuth2Client)); + } + + @GetMapping("/page") + @ApiOperation("获得OAuth2 客户端分页") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") + public CommonResult> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) { + PageResult pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO); + return success(OAuth2ClientConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.java new file mode 100644 index 0000000..cf58519 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.java @@ -0,0 +1,159 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "管理后台 - OAuth2.0 授权") +@RestController +@RequestMapping("/system/oauth2") +@Validated +@Slf4j +public class OAuth2Controller { + +// POST oauth/token TokenEndpoint:Password、Implicit、Code、Refresh Token + +// POST oauth/check_token CheckTokenEndpoint + +// DELETE oauth/token ConsumerTokenServices#revokeToken + +// GET oauth/authorize AuthorizationEndpoint + + @Resource + private OAuth2GrantService oAuth2GrantService; + @Resource + private OAuth2ClientService oauth2ClientService; + @Resource + private OAuth2ApproveService oauth2ApproveService; + + @GetMapping("/authorize") + @ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用") + @ApiImplicitParams({ + @ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class), + @ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class), + @ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 多个使用空格分隔 + @ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class), + @ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class) + }) + public CommonResult authorize(@RequestParam("response_type") String responseType, + @RequestParam("client_id") String clientId, + @RequestParam(value = "scope", required = false) String scope, + @RequestParam("redirect_uri") String redirectUri, + @RequestParam(value = "state", required = false) String state) { + List scopes = StrUtil.split(scope, ' '); + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1.1 校验 responseType 是否满足 code 或者 token 值 + OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType); + // 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内 + oauth2ClientService.validOAuthClientFromCache(clientId, grantTypeEnum.getGrantType(), scopes, redirectUri); + + // 2. 判断是否满足自动授权(满足) + boolean approved = oauth2ApproveService.checkForPreApproval(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes); + if (approved) { + // 2.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 + if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { + return success(getAuthorizationCodeRedirect()); + } + return success(getImplicitGrantRedirect()); + } + + // 3. 不满足自动授权,则返回授权相关的展示信息 + return null; + } + + @PostMapping("/authorize") + @ApiOperation(value = "申请授权", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【提交】调用") + @ApiImplicitParams({ + @ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class), + @ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class), + @ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 使用 Map 格式,Spring MVC 暂时不支持这么接收参数 + @ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class), + @ApiImplicitParam(name = "autoApprove", required = true, value = "用户是否接受", example = "true", dataTypeClass = Boolean.class), + @ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class) + }) + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 + // 场景一:【自动授权 autoApprove = true】刚进入 authorize.vue 界面,调用该接口,用户历史已经给该应用做过对应的授权,或者 OAuth2Client 支持该 scope 的自动授权 + // 场景二:【手动授权 autoApprove = false】在 authorize.vue 界面,用户选择好 scope 授权范围,调用该接口,进行授权。此时,approved 为 true 或者 false + // 因为前后端分离,Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL,剩余交给前端处理 + public CommonResult approveOrDeny(@RequestParam("response_type") String responseType, + @RequestParam("client_id") String clientId, + @RequestParam(value = "scope", required = false) String scope, + @RequestParam("redirect_uri") String redirectUri, + @RequestParam(value = "autoApprove") Boolean autoApprove, + @RequestParam(value = "state", required = false) String state) { + @SuppressWarnings("unchecked") + Map scopes = JsonUtils.parseObject(scope, Map.class); + scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap()); + // TODO 芋艿:针对 approved + scopes 在看看 spring security 的实现 + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1.1 校验 responseType 是否满足 code 或者 token 值 + OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType); + // 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内 + oauth2ClientService.validOAuthClientFromCache(clientId, grantTypeEnum.getGrantType(), scopes.keySet(), redirectUri); + + // 2.1 假设 approved 为 null,说明是场景一 + if (Boolean.TRUE.equals(autoApprove)) { + // 如果无法自动授权通过,则返回空 url,前端不进行跳转 + if (!oauth2ApproveService.checkForPreApproval(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes.keySet())) { + return success(null); + } + } else { // 2.2 假设 approved 非 null,说明是场景二 + // 如果计算后不通过,则跳转一个错误链接 + if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes)) { + return success("TODO"); + } + } + + // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 + if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { + return success(getAuthorizationCodeRedirect()); + } + // 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向 + return success(getImplicitGrantRedirect()); + } + + private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) { + if (StrUtil.equals(responseType, "code")) { + return OAuth2GrantTypeEnum.AUTHORIZATION_CODE; + } + if (StrUtil.equalsAny(responseType, "token")) { + return OAuth2GrantTypeEnum.IMPLICIT; + } + throw exception0(BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token"); + } + + private String getImplicitGrantRedirect() { + return ""; + } + + private String getAuthorizationCodeRedirect() { + return ""; + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java new file mode 100644 index 0000000..3adacf4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO; +import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - OAuth2.0 令牌") +@RestController +@RequestMapping("/system/oauth2-token") +public class OAuth2TokenController { + + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private AdminAuthService authService; + + @GetMapping("/page") + @ApiOperation(value = "获得访问令牌分页", notes = "只返回有效期内的") + @PreAuthorize("@ss.hasPermission('system:oauth2-token:page')") + public CommonResult> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) { + PageResult pageResult = oauth2TokenService.getAccessTokenPage(reqVO); + return success(OAuth2TokenConvert.INSTANCE.convert(pageResult)); + } + + @DeleteMapping("/delete") + @ApiOperation("删除访问令牌") + @ApiImplicitParam(name = "accessToken", value = "访问令牌", required = true, dataTypeClass = String.class, example = "tudou") + @PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')") + public CommonResult deleteAccessToken(@RequestParam("accessToken") String accessToken) { + authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType()); + return success(true); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientBaseVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientBaseVO.java new file mode 100755 index 0000000..786bc52 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientBaseVO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** +* OAuth2 客户端 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class OAuth2ClientBaseVO { + + @ApiModelProperty(value = "客户端编号", required = true) + @NotNull(message = "客户端编号不能为空") + private String clientId; + + @ApiModelProperty(value = "客户端密钥", required = true) + @NotNull(message = "客户端密钥不能为空") + private String secret; + + @ApiModelProperty(value = "应用名", required = true) + @NotNull(message = "应用名不能为空") + private String name; + + @ApiModelProperty(value = "应用图标", required = true) + @NotNull(message = "应用图标不能为空") + @URL(message = "应用图标的地址不正确") + private String logo; + + @ApiModelProperty(value = "应用描述") + private String description; + + @ApiModelProperty(value = "状态", required = true) + @NotNull(message = "状态不能为空") + private Integer status; + + @ApiModelProperty(value = "访问令牌的有效期", required = true) + @NotNull(message = "访问令牌的有效期不能为空") + private Integer accessTokenValiditySeconds; + + @ApiModelProperty(value = "刷新令牌的有效期", required = true) + @NotNull(message = "刷新令牌的有效期不能为空") + private Integer refreshTokenValiditySeconds; + + @ApiModelProperty(value = "可重定向的 URI 地址", required = true) + @NotNull(message = "可重定向的 URI 地址不能为空") + private List<@NotEmpty(message = "重定向的 URI 不能为空") + @URL(message = "重定向的 URI 格式不正确") String> redirectUris; + + @ApiModelProperty(value = "授权类型", required = true, example = "password", notes = "参见 OAuth2GrantTypeEnum 枚举") + @NotNull(message = "授权类型不能为空") + private List authorizedGrantTypes; + + @ApiModelProperty(value = "授权范围", example = "user_info") + private List scopes; + + @ApiModelProperty(value = "自动通过的授权范围", example = "user_info") + private List autoApproveScopes; + + @ApiModelProperty(value = "权限", example = "system:user:query") + private List authorities; + + @ApiModelProperty(value = "资源", example = "1024") + private List resourceIds; + + @ApiModelProperty(value = "附加信息", example = "{yunai: true}") + private String additionalInformation; + + @AssertTrue(message = "附加信息必须是 JSON 格式") + public boolean isAdditionalInformationJson() { + return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientCreateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientCreateReqVO.java new file mode 100755 index 0000000..b241277 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientCreateReqVO.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import lombok.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - OAuth2 客户端创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OAuth2ClientCreateReqVO extends OAuth2ClientBaseVO { + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java new file mode 100755 index 0000000..b6d2a21 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import lombok.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +@ApiModel("管理后台 - OAuth2 客户端分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OAuth2ClientPageReqVO extends PageParam { + + @ApiModelProperty(value = "应用名") + private String name; + + @ApiModelProperty(value = "状态") + private Integer status; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java new file mode 100755 index 0000000..e0df90f --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - OAuth2 客户端 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OAuth2ClientRespVO extends OAuth2ClientBaseVO { + + @ApiModelProperty(value = "编号", required = true) + private Long id; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientUpdateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientUpdateReqVO.java new file mode 100755 index 0000000..3b1d2a0 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientUpdateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - OAuth2 客户端更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OAuth2ClientUpdateReqVO extends OAuth2ClientBaseVO { + + @ApiModelProperty(value = "编号", required = true) + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java new file mode 100644 index 0000000..65103ad --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@ApiModel("管理后台 - 访问令牌分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2AccessTokenPageReqVO extends PageParam { + + @ApiModelProperty(value = "用户编号", required = true, example = "666") + private Long userId; + + @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") + private Integer userType; + + @ApiModelProperty(value = "客户端编号", required = true, example = "2") + private String clientId; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java new file mode 100644 index 0000000..b1d5a48 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@ApiModel("管理后台 - 访问令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2AccessTokenRespVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "访问令牌", required = true, example = "tudou") + private String accessToken; + + @ApiModelProperty(value = "刷新令牌", required = true, example = "nice") + private String refreshToken; + + @ApiModelProperty(value = "用户编号", required = true, example = "666") + private Long userId; + + @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") + private Integer userType; + + @ApiModelProperty(value = "客户端编号", required = true, example = "2") + private String clientId; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + + @ApiModelProperty(value = "过期时间", required = true) + private Date expiresTime; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java index 9f8a322..d03cf79 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2ClientConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2ClientConvert.java index 91ccb4e..021eea2 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2ClientConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2ClientConvert.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.system.convert.auth; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientRespVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientUpdateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java index 882f697..0530ebe 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.convert.auth; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO; import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java index 6fadaf5..b3d8e4e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.auth; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2ClientMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2ClientMapper.java index ce128e1..a3f9093 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2ClientMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2ClientMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.auth; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java index f41dd36..fc765c4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.mq.consumer.auth; import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; import cn.iocoder.yudao.module.system.mq.message.auth.OAuth2ClientRefreshMessage; -import cn.iocoder.yudao.module.system.service.auth.OAuth2ClientService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java index 5f67f96..ec8b31b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.service.auth; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import javax.validation.Valid; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index 66c00a2..55ffaae 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; @@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService; import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import com.google.common.annotations.VisibleForTesting; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminOAuth2Service.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminOAuth2Service.java deleted file mode 100644 index 7910e27..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminOAuth2Service.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; - -import java.util.Collection; - -/** - * 管理后台的 OAuth2 Service 接口 - * - * 将自身的 AdminUser 用户,授权给第三方应用,采用 OAuth2.0 的协议。 - * - * 问题:为什么自身也作为一个第三方应用,也走这套流程呢? - * 回复:当然可以这么做,采用 Implicit 模式。考虑到大多数开发者使用不到这个特性,OAuth2.0 毕竟有一定学习成本,所以暂时没有采取这种方式。 - * - * @author 芋道源码 - */ -public interface AdminOAuth2Service { - - // ImplicitTokenGranter - OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, - String clientId, Collection scopes); - - // AuthorizationCodeTokenGranter - String grantAuthorizationCode(Long userId, Integer userType, - String clientId, Collection scopes, - String redirectUri, String state); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveService.java deleted file mode 100644 index 991e81b..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveService.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import java.util.Collection; - -/** - * OAuth2 批准 Service 接口 - * - * 从功能上,和 Spring Security OAuth 的 ApprovalStoreUserApprovalHandler 的功能,记录用户针对指定客户端的授权,减少手动确定。 - * - * @author 芋道源码 - */ -public interface OAuth2ApproveService { - - /** - * 获得指定用户,针对指定客户端的指定授权,是否通过 - * - * 参考 ApprovalStoreUserApprovalHandler 的 checkForPreApproval 方法 - * - * @param userId 用户编号 - * @param userType 用户类型 - * @param clientId 客户端编号 - * @param scopes 授权范围 - * @return 是否授权通过 - */ - boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection scopes); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveServiceImpl.java deleted file mode 100644 index 17d38a8..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ApproveServiceImpl.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import org.springframework.stereotype.Service; - -import java.util.Collection; - -/** - * OAuth2 批准 Service 实现类 - * - * @author 芋道源码 - */ -@Service -public class OAuth2ApproveServiceImpl implements OAuth2ApproveService { - - @Override - public boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection scopes) { - return false; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientService.java deleted file mode 100644 index 5915610..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientService.java +++ /dev/null @@ -1,87 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientUpdateReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; - -import javax.validation.Valid; -import java.util.Collection; - -/** - * OAuth2.0 Client Service 接口 - * - * 从功能上,和 JdbcClientDetailsService 的功能,提供客户端的操作 - * - * @author 芋道源码 - */ -public interface OAuth2ClientService { - - /** - * 初始化 OAuth2Client 的本地缓存 - */ - void initLocalCache(); - - /** - * 创建 OAuth2 客户端 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createOAuth2Client(@Valid OAuth2ClientCreateReqVO createReqVO); - - /** - * 更新 OAuth2 客户端 - * - * @param updateReqVO 更新信息 - */ - void updateOAuth2Client(@Valid OAuth2ClientUpdateReqVO updateReqVO); - - /** - * 删除 OAuth2 客户端 - * - * @param id 编号 - */ - void deleteOAuth2Client(Long id); - - /** - * 获得 OAuth2 客户端 - * - * @param id 编号 - * @return OAuth2 客户端 - */ - OAuth2ClientDO getOAuth2Client(Long id); - - /** - * 获得 OAuth2 客户端分页 - * - * @param pageReqVO 分页查询 - * @return OAuth2 客户端分页 - */ - PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO); - - /** - * 从缓存中,校验客户端是否合法 - * - * @return 客户端 - */ - default OAuth2ClientDO validOAuthClientFromCache(String clientId) { - return validOAuthClientFromCache(clientId, null, null, null); - } - - /** - * 从缓存中,校验客户端是否合法 - * - * 非空时,进行校验 - * - * @param clientId 客户端编号 - * @param authorizedGrantType 授权方式 - * @param scopes 授权范围 - * @param redirectUri 重定向地址 - * @return 客户端 - */ - OAuth2ClientDO validOAuthClientFromCache(String clientId, String authorizedGrantType, - Collection scopes, String redirectUri); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImpl.java deleted file mode 100644 index c56562e..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImpl.java +++ /dev/null @@ -1,203 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.string.StrUtils; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientUpdateReqVO; -import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2ClientMapper; -import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; -import com.google.common.annotations.VisibleForTesting; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.PostConstruct; -import javax.annotation.Resource; -import java.util.*; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; - -/** - * OAuth2.0 Client Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -@Slf4j -public class OAuth2ClientServiceImpl implements OAuth2ClientService { - - /** - * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 - * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 - */ - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; - - /** - * 客户端缓存 - * key:客户端编号 {@link OAuth2ClientDO#getClientId()} ()} - * - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 - */ - @Getter - private volatile Map clientCache; - /** - * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新 - */ - @Getter - private volatile Date maxUpdateTime; - - @Resource - private OAuth2ClientMapper oauth2ClientMapper; - - @Resource - private OAuth2ClientProducer oauth2ClientProducer; - - /** - * 初始化 {@link #clientCache} 缓存 - */ - @Override - @PostConstruct - public void initLocalCache() { - // 获取客户端列表,如果有更新 - List tenantList = loadOAuth2ClientIfUpdate(maxUpdateTime); - if (CollUtil.isEmpty(tenantList)) { - return; - } - - // 写入缓存 - clientCache = convertMap(tenantList, OAuth2ClientDO::getClientId); - maxUpdateTime = getMaxValue(tenantList, OAuth2ClientDO::getUpdateTime); - log.info("[initLocalCache][初始化 OAuth2Client 数量为 {}]", tenantList.size()); - } - - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) - public void schedulePeriodicRefresh() { - initLocalCache(); - } - - /** - * 如果客户端发生变化,从数据库中获取最新的全量客户端。 - * 如果未发生变化,则返回空 - * - * @param maxUpdateTime 当前客户端的最大更新时间 - * @return 客户端列表 - */ - private List loadOAuth2ClientIfUpdate(Date maxUpdateTime) { - // 第一步,判断是否要更新。 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 - log.info("[loadOAuth2ClientIfUpdate][首次加载全量客户端]"); - } else { // 判断数据库中是否有更新的客户端 - if (oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { - return null; - } - log.info("[loadOAuth2ClientIfUpdate][增量加载全量客户端]"); - } - // 第二步,如果有更新,则从数据库加载所有客户端 - return oauth2ClientMapper.selectList(); - } - - @Override - public Long createOAuth2Client(OAuth2ClientCreateReqVO createReqVO) { - validateClientIdExists(null, createReqVO.getClientId()); - // 插入 - OAuth2ClientDO oauth2Client = OAuth2ClientConvert.INSTANCE.convert(createReqVO); - oauth2ClientMapper.insert(oauth2Client); - // 发送刷新消息 - oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); - return oauth2Client.getId(); - } - - @Override - public void updateOAuth2Client(OAuth2ClientUpdateReqVO updateReqVO) { - // 校验存在 - validateOAuth2ClientExists(updateReqVO.getId()); - // 校验 Client 未被占用 - validateClientIdExists(updateReqVO.getId(), updateReqVO.getClientId()); - - // 更新 - OAuth2ClientDO updateObj = OAuth2ClientConvert.INSTANCE.convert(updateReqVO); - oauth2ClientMapper.updateById(updateObj); - // 发送刷新消息 - oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); - } - - @Override - public void deleteOAuth2Client(Long id) { - // 校验存在 - validateOAuth2ClientExists(id); - // 删除 - oauth2ClientMapper.deleteById(id); - // 发送刷新消息 - oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); - } - - private void validateOAuth2ClientExists(Long id) { - if (oauth2ClientMapper.selectById(id) == null) { - throw exception(OAUTH2_CLIENT_NOT_EXISTS); - } - } - - @VisibleForTesting - public void validateClientIdExists(Long id, String clientId) { - OAuth2ClientDO client = oauth2ClientMapper.selectByClientId(clientId); - if (client == null) { - return; - } - // 如果 id 为空,说明不用比较是否为相同 id 的客户端 - if (id == null) { - throw exception(OAUTH2_CLIENT_EXISTS); - } - if (!client.getClientId().equals(clientId)) { - throw exception(OAUTH2_CLIENT_EXISTS); - } - } - - @Override - public OAuth2ClientDO getOAuth2Client(Long id) { - return oauth2ClientMapper.selectById(id); - } - - @Override - public PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) { - return oauth2ClientMapper.selectPage(pageReqVO); - } - - @Override - public OAuth2ClientDO validOAuthClientFromCache(String clientId, String authorizedGrantType, Collection scopes, String redirectUri) { - // 校验客户端存在、且开启 - OAuth2ClientDO client = clientCache.get(clientId); - if (client == null) { - throw exception(OAUTH2_CLIENT_EXISTS); - } - if (Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { - throw exception(OAUTH2_CLIENT_DISABLE); - } - - // 校验授权方式 - if (StrUtil.isNotEmpty(authorizedGrantType) && !CollUtil.contains(client.getAuthorizedGrantTypes(), authorizedGrantType)) { - throw exception(OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); - } - // 校验授权范围 - if (CollUtil.isNotEmpty(scopes) && !CollUtil.containsAll(client.getScopes(), scopes)) { - throw exception(OAUTH2_CLIENT_SCOPE_OVER); - } - // 校验回调地址 - if (StrUtil.isNotEmpty(redirectUri) && !StrUtils.startWithAny(redirectUri, client.getRedirectUris())) { - throw exception(OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH); - } - return client; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2CodeService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2CodeService.java deleted file mode 100644 index a4a38b1..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2CodeService.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -/** - * OAuth2.0 授权码 Service 接口 - * - * 从功能上,和 Spring Security OAuth 的 JdbcAuthorizationCodeServices 的功能,提供授权码的操作 - * - * @author 芋道源码 - */ -public interface OAuth2CodeService { - - - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenService.java deleted file mode 100644 index ad373bc..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenService.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; - -/** - * OAuth2.0 Token Service 接口 - * - * 从功能上,和 Spring Security OAuth 的 DefaultTokenServices + JdbcTokenStore 的功能,提供访问令牌、刷新令牌的操作 - * - * @author 芋道源码 - */ -public interface OAuth2TokenService { - - /** - * 创建访问令牌 - * 注意:该流程中,会包含创建刷新令牌的创建 - * - * 参考 DefaultTokenServices 的 createAccessToken 方法 - * - * @param userId 用户编号 - * @param userType 用户类型 - * @param clientId 客户端编号 - * @return 访问令牌的信息 - */ - OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId); - - /** - * 刷新访问令牌 - * - * 参考 DefaultTokenServices 的 refreshAccessToken 方法 - * - * @param refreshToken 刷新令牌 - * @param clientId 客户端编号 - * @return 访问令牌的信息 - */ - OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId); - - /** - * 获得访问令牌 - * - * 参考 DefaultTokenServices 的 getAccessToken 方法 - * - * @param accessToken 访问令牌 - * @return 访问令牌的信息 - */ - OAuth2AccessTokenDO getAccessToken(String accessToken); - - /** - * 校验访问令牌 - * - * @param accessToken 访问令牌 - * @return 访问令牌的信息 - */ - OAuth2AccessTokenDO checkAccessToken(String accessToken); - - /** - * 移除访问令牌 - * 注意:该流程中,会移除相关的刷新令牌 - * - * 参考 DefaultTokenServices 的 revokeToken 方法 - * - * @param accessToken 刷新令牌 - * @return 访问令牌的信息 - */ - OAuth2AccessTokenDO removeAccessToken(String accessToken); - - /** - * 获得访问令牌分页 - * - * @param reqVO 请求 - * @return 访问令牌分页 - */ - PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenServiceImpl.java deleted file mode 100644 index 31b17be..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenServiceImpl.java +++ /dev/null @@ -1,163 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; -import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2RefreshTokenDO; -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2AccessTokenMapper; -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2RefreshTokenMapper; -import cn.iocoder.yudao.module.system.dal.redis.auth.OAuth2AccessTokenRedisDAO; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.util.Calendar; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -/** - * OAuth2.0 Token Service 实现类 - * - * @author 芋道源码 - */ -@Service -public class OAuth2TokenServiceImpl implements OAuth2TokenService { - - @Resource - private OAuth2AccessTokenMapper oauth2AccessTokenMapper; - @Resource - private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper; - - @Resource - private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO; - - @Resource - private OAuth2ClientService oauth2ClientService; - - @Override - @Transactional - public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId) { - OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); - // 创建刷新令牌 - OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO); - // 创建访问令牌 - return createOAuth2AccessToken(refreshTokenDO, clientDO); - } - - @Override - public OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId) { - // 查询访问令牌 - OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(refreshToken); - if (refreshTokenDO == null) { - throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "无效的刷新令牌"); - } - - // 校验 Client 匹配 - OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); - if (ObjectUtil.notEqual(clientId, refreshTokenDO.getClientId())) { - throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "刷新令牌的客户端编号不正确"); - } - - // 移除相关的访问令牌 - List accessTokenDOs = oauth2AccessTokenMapper.selectListByRefreshToken(refreshToken); - if (CollUtil.isNotEmpty(accessTokenDOs)) { - oauth2AccessTokenMapper.deleteBatchIds(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getId)); - oauth2AccessTokenRedisDAO.deleteList(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getAccessToken)); - } - - // 已过期的情况下,删除刷新令牌 - if (DateUtils.isExpired(refreshTokenDO.getExpiresTime())) { - oauth2AccessTokenMapper.deleteById(refreshTokenDO.getId()); - throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "刷新令牌已过期"); - } - - // 创建访问令牌 - return createOAuth2AccessToken(refreshTokenDO, clientDO); - } - - @Override - public OAuth2AccessTokenDO getAccessToken(String accessToken) { - // 优先从 Redis 中获取 - OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken); - if (accessTokenDO != null) { - return accessTokenDO; - } - - // 获取不到,从 MySQL 中获取 - accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); - // 如果在 MySQL 存在,则往 Redis 中写入 - if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) { - oauth2AccessTokenRedisDAO.set(accessTokenDO); - } - return accessTokenDO; - } - - @Override - public OAuth2AccessTokenDO checkAccessToken(String accessToken) { - OAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken); - if (accessTokenDO == null) { - throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在"); - } - if (DateUtils.isExpired(accessTokenDO.getExpiresTime())) { - throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌已过期"); - } - return accessTokenDO; - } - - @Override - public OAuth2AccessTokenDO removeAccessToken(String accessToken) { - // 删除访问令牌 - OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); - if (accessTokenDO == null) { - return null; - } - oauth2AccessTokenMapper.deleteById(accessTokenDO.getId()); - oauth2AccessTokenRedisDAO.delete(accessToken); - // 删除刷新令牌 - oauth2RefreshTokenMapper.deleteByRefreshToken(accessTokenDO.getRefreshToken()); - return accessTokenDO; - } - - @Override - public PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO) { - return oauth2AccessTokenMapper.selectPage(reqVO); - } - - private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) { - OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken()) - .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()).setClientId(clientDO.getClientId()) - .setRefreshToken(refreshTokenDO.getRefreshToken()) - .setExpiresTime(DateUtils.addDate(Calendar.SECOND, clientDO.getAccessTokenValiditySeconds())); - accessTokenDO.setTenantId(TenantContextHolder.getTenantId()); // 手动设置租户编号,避免缓存到 Redis 的时候,无对应的租户编号 - oauth2AccessTokenMapper.insert(accessTokenDO); - // 记录到 Redis 中 - oauth2AccessTokenRedisDAO.set(accessTokenDO); - return accessTokenDO; - } - - private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO) { - OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken()) - .setUserId(userId).setUserType(userType).setClientId(clientDO.getClientId()) - .setExpiresTime(DateUtils.addDate(Calendar.SECOND, clientDO.getRefreshTokenValiditySeconds())); - oauth2RefreshTokenMapper.insert(refreshToken); - return refreshToken; - } - - private static String generateAccessToken() { - return IdUtil.fastSimpleUUID(); - } - - private static String generateRefreshToken() { - return IdUtil.fastSimpleUUID(); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java new file mode 100644 index 0000000..bd1f168 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import java.util.Collection; +import java.util.Map; + +/** + * OAuth2 批准 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 ApprovalStoreUserApprovalHandler 的功能,记录用户针对指定客户端的授权,减少手动确定。 + * + * @author 芋道源码 + */ +public interface OAuth2ApproveService { + + /** + * 获得指定用户,针对指定客户端的指定授权,是否通过 + * + * 参考 ApprovalStoreUserApprovalHandler 的 checkForPreApproval 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 是否授权通过 + */ + boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection scopes); + + /** + * 在用户发起批准时,基于 scopes 的选项,计算最终是否通过 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 是否授权通过 + */ + boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map scopes); + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java new file mode 100644 index 0000000..76e9af6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Map; + +/** + * OAuth2 批准 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2ApproveServiceImpl implements OAuth2ApproveService { + + @Override + public boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection scopes) { + return true; + } + + @Override + public boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map scopes) { + return true; + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java new file mode 100644 index 0000000..3c1408c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; + +import javax.validation.Valid; +import java.util.Collection; + +/** + * OAuth2.0 Client Service 接口 + * + * 从功能上,和 JdbcClientDetailsService 的功能,提供客户端的操作 + * + * @author 芋道源码 + */ +public interface OAuth2ClientService { + + /** + * 初始化 OAuth2Client 的本地缓存 + */ + void initLocalCache(); + + /** + * 创建 OAuth2 客户端 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createOAuth2Client(@Valid OAuth2ClientCreateReqVO createReqVO); + + /** + * 更新 OAuth2 客户端 + * + * @param updateReqVO 更新信息 + */ + void updateOAuth2Client(@Valid OAuth2ClientUpdateReqVO updateReqVO); + + /** + * 删除 OAuth2 客户端 + * + * @param id 编号 + */ + void deleteOAuth2Client(Long id); + + /** + * 获得 OAuth2 客户端 + * + * @param id 编号 + * @return OAuth2 客户端 + */ + OAuth2ClientDO getOAuth2Client(Long id); + + /** + * 获得 OAuth2 客户端分页 + * + * @param pageReqVO 分页查询 + * @return OAuth2 客户端分页 + */ + PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO); + + /** + * 从缓存中,校验客户端是否合法 + * + * @return 客户端 + */ + default OAuth2ClientDO validOAuthClientFromCache(String clientId) { + return validOAuthClientFromCache(clientId, null, null, null); + } + + /** + * 从缓存中,校验客户端是否合法 + * + * 非空时,进行校验 + * + * @param clientId 客户端编号 + * @param authorizedGrantType 授权方式 + * @param scopes 授权范围 + * @param redirectUri 重定向地址 + * @return 客户端 + */ + OAuth2ClientDO validOAuthClientFromCache(String clientId, String authorizedGrantType, + Collection scopes, String redirectUri); + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java new file mode 100644 index 0000000..501c9ee --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java @@ -0,0 +1,203 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; +import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2ClientMapper; +import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; +import com.google.common.annotations.VisibleForTesting; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * OAuth2.0 Client Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class OAuth2ClientServiceImpl implements OAuth2ClientService { + + /** + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 + */ + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; + + /** + * 客户端缓存 + * key:客户端编号 {@link OAuth2ClientDO#getClientId()} ()} + * + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 + */ + @Getter + private volatile Map clientCache; + /** + * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新 + */ + @Getter + private volatile Date maxUpdateTime; + + @Resource + private OAuth2ClientMapper oauth2ClientMapper; + + @Resource + private OAuth2ClientProducer oauth2ClientProducer; + + /** + * 初始化 {@link #clientCache} 缓存 + */ + @Override + @PostConstruct + public void initLocalCache() { + // 获取客户端列表,如果有更新 + List tenantList = loadOAuth2ClientIfUpdate(maxUpdateTime); + if (CollUtil.isEmpty(tenantList)) { + return; + } + + // 写入缓存 + clientCache = convertMap(tenantList, OAuth2ClientDO::getClientId); + maxUpdateTime = getMaxValue(tenantList, OAuth2ClientDO::getUpdateTime); + log.info("[initLocalCache][初始化 OAuth2Client 数量为 {}]", tenantList.size()); + } + + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) + public void schedulePeriodicRefresh() { + initLocalCache(); + } + + /** + * 如果客户端发生变化,从数据库中获取最新的全量客户端。 + * 如果未发生变化,则返回空 + * + * @param maxUpdateTime 当前客户端的最大更新时间 + * @return 客户端列表 + */ + private List loadOAuth2ClientIfUpdate(Date maxUpdateTime) { + // 第一步,判断是否要更新。 + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 + log.info("[loadOAuth2ClientIfUpdate][首次加载全量客户端]"); + } else { // 判断数据库中是否有更新的客户端 + if (oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { + return null; + } + log.info("[loadOAuth2ClientIfUpdate][增量加载全量客户端]"); + } + // 第二步,如果有更新,则从数据库加载所有客户端 + return oauth2ClientMapper.selectList(); + } + + @Override + public Long createOAuth2Client(OAuth2ClientCreateReqVO createReqVO) { + validateClientIdExists(null, createReqVO.getClientId()); + // 插入 + OAuth2ClientDO oauth2Client = OAuth2ClientConvert.INSTANCE.convert(createReqVO); + oauth2ClientMapper.insert(oauth2Client); + // 发送刷新消息 + oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); + return oauth2Client.getId(); + } + + @Override + public void updateOAuth2Client(OAuth2ClientUpdateReqVO updateReqVO) { + // 校验存在 + validateOAuth2ClientExists(updateReqVO.getId()); + // 校验 Client 未被占用 + validateClientIdExists(updateReqVO.getId(), updateReqVO.getClientId()); + + // 更新 + OAuth2ClientDO updateObj = OAuth2ClientConvert.INSTANCE.convert(updateReqVO); + oauth2ClientMapper.updateById(updateObj); + // 发送刷新消息 + oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); + } + + @Override + public void deleteOAuth2Client(Long id) { + // 校验存在 + validateOAuth2ClientExists(id); + // 删除 + oauth2ClientMapper.deleteById(id); + // 发送刷新消息 + oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); + } + + private void validateOAuth2ClientExists(Long id) { + if (oauth2ClientMapper.selectById(id) == null) { + throw exception(OAUTH2_CLIENT_NOT_EXISTS); + } + } + + @VisibleForTesting + public void validateClientIdExists(Long id, String clientId) { + OAuth2ClientDO client = oauth2ClientMapper.selectByClientId(clientId); + if (client == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的客户端 + if (id == null) { + throw exception(OAUTH2_CLIENT_EXISTS); + } + if (!client.getClientId().equals(clientId)) { + throw exception(OAUTH2_CLIENT_EXISTS); + } + } + + @Override + public OAuth2ClientDO getOAuth2Client(Long id) { + return oauth2ClientMapper.selectById(id); + } + + @Override + public PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) { + return oauth2ClientMapper.selectPage(pageReqVO); + } + + @Override + public OAuth2ClientDO validOAuthClientFromCache(String clientId, String authorizedGrantType, Collection scopes, String redirectUri) { + // 校验客户端存在、且开启 + OAuth2ClientDO client = clientCache.get(clientId); + if (client == null) { + throw exception(OAUTH2_CLIENT_EXISTS); + } + if (Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + throw exception(OAUTH2_CLIENT_DISABLE); + } + + // 校验授权方式 + if (StrUtil.isNotEmpty(authorizedGrantType) && !CollUtil.contains(client.getAuthorizedGrantTypes(), authorizedGrantType)) { + throw exception(OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); + } + // 校验授权范围 + if (CollUtil.isNotEmpty(scopes) && !CollUtil.containsAll(client.getScopes(), scopes)) { + throw exception(OAUTH2_CLIENT_SCOPE_OVER); + } + // 校验回调地址 + if (StrUtil.isNotEmpty(redirectUri) && !StrUtils.startWithAny(redirectUri, client.getRedirectUris())) { + throw exception(OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH); + } + return client; + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java new file mode 100644 index 0000000..37b5f54 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +/** + * OAuth2.0 授权码 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 JdbcAuthorizationCodeServices 的功能,提供授权码的操作 + * + * @author 芋道源码 + */ +public interface OAuth2CodeService { + + + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java new file mode 100644 index 0000000..35e1a26 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; + +import java.util.Collection; + +/** + * OAuth2 授予 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 TokenGranter 的功能,提供访问令牌、刷新令牌的操作 + * + * 将自身的 AdminUser 用户,授权给第三方应用,采用 OAuth2.0 的协议。 + * + * 问题:为什么自身也作为一个第三方应用,也走这套流程呢? + * 回复:当然可以这么做,采用 Implicit 模式。考虑到大多数开发者使用不到这个特性,OAuth2.0 毕竟有一定学习成本,所以暂时没有采取这种方式。 + * + * @author 芋道源码 + */ +public interface OAuth2GrantService { + + // ImplicitTokenGranter + OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, Collection scopes); + + // AuthorizationCodeTokenGranter + String grantAuthorizationCode(Long userId, Integer userType, + String clientId, Collection scopes, + String redirectUri, String state); + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java new file mode 100644 index 0000000..29b658a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; +import org.springframework.stereotype.Service; + +import java.util.Collection; + +/** + * OAuth2 授予 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2GrantServiceImpl implements OAuth2GrantService { + + @Override + public OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, Collection scopes) { + return null; + } + + @Override + public String grantAuthorizationCode(Long userId, Integer userType, + String clientId, Collection scopes, + String redirectUri, String state) { + return null; + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java new file mode 100644 index 0000000..d8fbf7b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; + +/** + * OAuth2.0 Token Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 DefaultTokenServices + JdbcTokenStore 的功能,提供访问令牌、刷新令牌的操作 + * + * @author 芋道源码 + */ +public interface OAuth2TokenService { + + /** + * 创建访问令牌 + * 注意:该流程中,会包含创建刷新令牌的创建 + * + * 参考 DefaultTokenServices 的 createAccessToken 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId); + + /** + * 刷新访问令牌 + * + * 参考 DefaultTokenServices 的 refreshAccessToken 方法 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId); + + /** + * 获得访问令牌 + * + * 参考 DefaultTokenServices 的 getAccessToken 方法 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO getAccessToken(String accessToken); + + /** + * 校验访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO checkAccessToken(String accessToken); + + /** + * 移除访问令牌 + * 注意:该流程中,会移除相关的刷新令牌 + * + * 参考 DefaultTokenServices 的 revokeToken 方法 + * + * @param accessToken 刷新令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO removeAccessToken(String accessToken); + + /** + * 获得访问令牌分页 + * + * @param reqVO 请求 + * @return 访问令牌分页 + */ + PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO); + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java new file mode 100644 index 0000000..410dc37 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2RefreshTokenDO; +import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2AccessTokenMapper; +import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2RefreshTokenMapper; +import cn.iocoder.yudao.module.system.dal.redis.auth.OAuth2AccessTokenRedisDAO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Calendar; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * OAuth2.0 Token Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2TokenServiceImpl implements OAuth2TokenService { + + @Resource + private OAuth2AccessTokenMapper oauth2AccessTokenMapper; + @Resource + private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper; + + @Resource + private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO; + + @Resource + private OAuth2ClientService oauth2ClientService; + + @Override + @Transactional + public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId) { + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + // 创建刷新令牌 + OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO); + // 创建访问令牌 + return createOAuth2AccessToken(refreshTokenDO, clientDO); + } + + @Override + public OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId) { + // 查询访问令牌 + OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(refreshToken); + if (refreshTokenDO == null) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "无效的刷新令牌"); + } + + // 校验 Client 匹配 + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + if (ObjectUtil.notEqual(clientId, refreshTokenDO.getClientId())) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "刷新令牌的客户端编号不正确"); + } + + // 移除相关的访问令牌 + List accessTokenDOs = oauth2AccessTokenMapper.selectListByRefreshToken(refreshToken); + if (CollUtil.isNotEmpty(accessTokenDOs)) { + oauth2AccessTokenMapper.deleteBatchIds(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getId)); + oauth2AccessTokenRedisDAO.deleteList(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getAccessToken)); + } + + // 已过期的情况下,删除刷新令牌 + if (DateUtils.isExpired(refreshTokenDO.getExpiresTime())) { + oauth2AccessTokenMapper.deleteById(refreshTokenDO.getId()); + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "刷新令牌已过期"); + } + + // 创建访问令牌 + return createOAuth2AccessToken(refreshTokenDO, clientDO); + } + + @Override + public OAuth2AccessTokenDO getAccessToken(String accessToken) { + // 优先从 Redis 中获取 + OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken); + if (accessTokenDO != null) { + return accessTokenDO; + } + + // 获取不到,从 MySQL 中获取 + accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); + // 如果在 MySQL 存在,则往 Redis 中写入 + if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) { + oauth2AccessTokenRedisDAO.set(accessTokenDO); + } + return accessTokenDO; + } + + @Override + public OAuth2AccessTokenDO checkAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken); + if (accessTokenDO == null) { + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在"); + } + if (DateUtils.isExpired(accessTokenDO.getExpiresTime())) { + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌已过期"); + } + return accessTokenDO; + } + + @Override + public OAuth2AccessTokenDO removeAccessToken(String accessToken) { + // 删除访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); + if (accessTokenDO == null) { + return null; + } + oauth2AccessTokenMapper.deleteById(accessTokenDO.getId()); + oauth2AccessTokenRedisDAO.delete(accessToken); + // 删除刷新令牌 + oauth2RefreshTokenMapper.deleteByRefreshToken(accessTokenDO.getRefreshToken()); + return accessTokenDO; + } + + @Override + public PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO) { + return oauth2AccessTokenMapper.selectPage(reqVO); + } + + private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) { + OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken()) + .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()).setClientId(clientDO.getClientId()) + .setRefreshToken(refreshTokenDO.getRefreshToken()) + .setExpiresTime(DateUtils.addDate(Calendar.SECOND, clientDO.getAccessTokenValiditySeconds())); + accessTokenDO.setTenantId(TenantContextHolder.getTenantId()); // 手动设置租户编号,避免缓存到 Redis 的时候,无对应的租户编号 + oauth2AccessTokenMapper.insert(accessTokenDO); + // 记录到 Redis 中 + oauth2AccessTokenRedisDAO.set(accessTokenDO); + return accessTokenDO; + } + + private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO) { + OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken()) + .setUserId(userId).setUserType(userType).setClientId(clientDO.getClientId()) + .setExpiresTime(DateUtils.addDate(Calendar.SECOND, clientDO.getRefreshTokenValiditySeconds())); + oauth2RefreshTokenMapper.insert(refreshToken); + return refreshToken; + } + + private static String generateAccessToken() { + return IdUtil.fastSimpleUUID(); + } + + private static String generateRefreshToken() { + return IdUtil.fastSimpleUUID(); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java index b68ef20..cd2e5f0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.util.AssertUtils; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthLoginReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthLoginRespVO; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginReqVO; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService; import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import org.junit.jupiter.api.BeforeEach; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java index 1fb688d..bc22d23 100755 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java @@ -3,12 +3,13 @@ package cn.iocoder.yudao.module.system.service.auth; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.client.OAuth2ClientUpdateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2ClientMapper; import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientServiceImpl; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; -- libgit2 0.21.4