From 5cf68961e1a5d7b310e6e9d8b9308c88c254b0dd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 10 May 2022 23:20:15 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BF=AE=E6=94=B9=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=9A=84=E5=AE=9E=E7=8E=B0=202.=20=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E5=88=B0=E4=BC=9A=E5=91=98=E7=AE=A1=E7=90=86=20OAuth2?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/config/SecurityProperties.java | 13 --- .../app/auth/AppAuthController.http | 9 +- .../app/auth/AppAuthController.java | 30 ++++--- .../app/auth/vo/AppAuthLoginRespVO.java | 17 +++- .../member/convert/auth/AuthConvert.java | 7 +- .../service/auth/MemberAuthService.java | 31 ++++--- .../service/auth/MemberAuthServiceImpl.java | 87 +++++++++---------- .../service/auth/MemberAuthServiceTest.java | 4 +- .../system/api/auth/OAuth2TokenApi.java | 29 ++++++- .../dto/OAuth2AccessTokenCreateReqDTO.java | 4 +- .../auth/dto/OAuth2AccessTokenRespDTO.java | 2 +- .../system/api/auth/OAuth2TokenApiImpl.java | 17 +++- .../controller/admin/auth/AuthController.java | 6 +- .../admin/auth/OAuth2TokenController.java | 50 +++++++++++ .../vo/token/OAuth2AccessTokenPageReqVO.java | 23 +++++ .../vo/token/OAuth2AccessTokenRespVO.java | 41 +++++++++ .../convert/auth/OAuth2TokenConvert.java | 7 ++ .../mysql/auth/OAuth2AccessTokenMapper.java | 13 +++ .../system/service/auth/AdminAuthService.java | 3 +- .../service/auth/AdminAuthServiceImpl.java | 19 ++-- .../service/auth/OAuth2TokenService.java | 10 +++ .../service/auth/OAuth2TokenServiceImpl.java | 7 ++ .../service/auth/AuthServiceImplTest.java | 4 +- yudao-server/pom.xml | 10 +-- .../src/main/resources/application-dev.yaml | 2 - .../src/main/resources/application-local.yaml | 2 - .../src/api/system/oauth2/oauth2Token.js | 18 ++++ yudao-ui-admin/src/api/system/session.js | 18 ---- .../{session => oauth2/token}/index.vue | 47 ++++++---- 29 files changed, 368 insertions(+), 162 deletions(-) create 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/token/OAuth2AccessTokenPageReqVO.java create 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-ui-admin/src/api/system/oauth2/oauth2Token.js delete mode 100644 yudao-ui-admin/src/api/system/session.js rename yudao-ui-admin/src/views/system/{session => oauth2/token}/index.vue (55%) diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java index 537463e94..a9373cd9c 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java @@ -6,7 +6,6 @@ import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import java.time.Duration; @ConfigurationProperties(prefix = "yudao.security") @Validated @@ -18,18 +17,6 @@ public class SecurityProperties { */ @NotEmpty(message = "Token Header 不能为空") private String tokenHeader; - /** - * Token 过期时间 - */ - @NotNull(message = "Token 过期时间不能为空") - private Duration tokenTimeout; - /** - * Session 过期时间 - * - * 当 User 用户超过当前时间未操作,则 Session 会过期 - */ - @NotNull(message = "Session 过期时间不能为空") - private Duration sessionTimeout; /** * mock 模式的开关 diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http index 210514699..b1704f55d 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http @@ -19,7 +19,7 @@ tenant-id: {{appTenentId}} } ### 请求 /sms-login 接口 => 成功 -POST {{appApi}}/member/sms-login +POST {{appApi}}/member/auth/sms-login Content-Type: application/json tenant-id: {{appTenentId}} @@ -29,7 +29,12 @@ tenant-id: {{appTenentId}} } ### 请求 /logout 接口 => 成功 -POST {{appApi}}/member/logout +POST {{appApi}}/member/auth/logout Content-Type: application/json Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 tenant-id: {{appTenentId}} + +### 请求 /auth/refresh-token 接口 => 成功 +POST {{appApi}}/member/auth/refresh-token?refreshToken=bc43d929094849a28b3a69f6e6940d70 +Content-Type: application/json +tenant-id: {{appTenentId}} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java index 696ead921..6532f7aca 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.framework.security.config.SecurityProperties; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; @@ -20,8 +21,6 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Api(tags = "用户 APP - 认证") @@ -40,8 +39,7 @@ public class AppAuthController { @PostMapping("/login") @ApiOperation("使用手机 + 密码登录") public CommonResult login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { - String token = authService.login(reqVO, getClientIP(), getUserAgent()); - return success(AppAuthLoginRespVO.builder().token(token).build()); + return success(authService.login(reqVO)); } @PostMapping("/logout") @@ -54,12 +52,20 @@ public class AppAuthController { return success(true); } + @PostMapping("/refresh-token") + @ApiOperation("刷新令牌") + @ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class) + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 + public CommonResult refreshToken(@RequestParam("refreshToken") String refreshToken) { + return success(authService.refreshToken(refreshToken)); + } + + // ========== 短信登录相关 ========== + @PostMapping("/sms-login") @ApiOperation("使用手机 + 验证码登录") public CommonResult smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { - String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent()); - // 返回结果 - return success(AppAuthLoginRespVO.builder().token(token).build()); + return success(authService.smsLogin(reqVO)); } @PostMapping("/send-sms-code") @@ -100,16 +106,14 @@ public class AppAuthController { @PostMapping("/social-quick-login") @ApiOperation(value = "社交快捷登录,使用 code 授权码", notes = "适合未登录的用户,但是社交账号已绑定用户") - public CommonResult socialLogin(@RequestBody @Valid AppAuthSocialQuickLoginReqVO reqVO) { - String token = authService.socialQuickLogin(reqVO, getClientIP(), getUserAgent()); - return success(AppAuthLoginRespVO.builder().token(token).build()); + public CommonResult socialQuickLogin(@RequestBody @Valid AppAuthSocialQuickLoginReqVO reqVO) { + return success(authService.socialQuickLogin(reqVO)); } @PostMapping("/social-bind-login") @ApiOperation(value = "社交绑定登录,使用 手机号 + 手机验证码", notes = "适合未登录的用户,进行登录 + 绑定") - public CommonResult socialLogin2(@RequestBody @Valid AppAuthSocialBindLoginReqVO reqVO) { - String token = authService.socialBindLogin(reqVO, getClientIP(), getUserAgent()); - return success(AppAuthLoginRespVO.builder().token(token).build()); + public CommonResult socialBindLogin(@RequestBody @Valid AppAuthSocialBindLoginReqVO reqVO) { + return success(authService.socialBindLogin(reqVO)); } } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java index 07ad43118..a63373071 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java @@ -7,14 +7,25 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -@ApiModel("用户 APP - 手机密码登录 Response VO") +import java.util.Date; + +@ApiModel("用户 APP - 登录 Response VO") @Data @NoArgsConstructor @AllArgsConstructor @Builder public class AppAuthLoginRespVO { - @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma") - private String token; + @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-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java index 9100c16e1..5a44d76bd 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java @@ -1,9 +1,8 @@ package cn.iocoder.yudao.module.member.convert.auth; -import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; -import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; 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; @@ -17,8 +16,6 @@ public interface AuthConvert { AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); - LoginUser convert(MemberUserDO bean); - SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialBindLoginReqVO reqVO); SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialQuickLoginReqVO reqVO); SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppSocialUserUnbindReqVO reqVO); @@ -27,4 +24,6 @@ public interface AuthConvert { SmsCodeUseReqDTO convert(AppAuthResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); + AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean); + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java index 6ded902c8..ded192217 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java @@ -17,11 +17,9 @@ public interface MemberAuthService { * 手机 + 密码登录 * * @param reqVO 登录信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 + * @return 登录结果 */ - String login(@Valid AppAuthLoginReqVO reqVO, String userIp, String userAgent); + AppAuthLoginRespVO login(@Valid AppAuthLoginReqVO reqVO); /** * 基于 token 退出登录 @@ -34,31 +32,25 @@ public interface MemberAuthService { * 手机 + 验证码登陆 * * @param reqVO 登陆信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 + * @return 登录结果 */ - String smsLogin(@Valid AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent); + AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO); /** * 社交登录,使用 code 授权码 * * @param reqVO 登录信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 + * @return 登录结果 */ - String socialQuickLogin(@Valid AppAuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent); + AppAuthLoginRespVO socialQuickLogin(@Valid AppAuthSocialQuickLoginReqVO reqVO); /** * 社交登录,使用 手机号 + 手机验证码 * * @param reqVO 登录信息 - * @param userIp 用户 IP - * @param userAgent 用户 UA - * @return 身份令牌,使用 JWT 方式 + * @return 登录结果 */ - String socialBindLogin(@Valid AppAuthSocialBindLoginReqVO reqVO, String userIp, String userAgent); + AppAuthLoginRespVO socialBindLogin(@Valid AppAuthSocialBindLoginReqVO reqVO); /** * 获得社交认证 URL @@ -90,4 +82,11 @@ public interface MemberAuthService { */ void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO); + /** + * 刷新访问令牌 + * + * @param refreshToken 刷新令牌 + * @return 登录结果 + */ + AppAuthLoginRespVO refreshToken(String refreshToken); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java index efcc7be5d..9fc86335e 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -6,17 +6,19 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.service.user.MemberUserService; -import cn.iocoder.yudao.module.system.api.auth.UserSessionApi; +import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi; +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.api.logger.LoginLogApi; 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.api.social.SocialUserApi; +import cn.iocoder.yudao.module.system.enums.auth.OAuth2ClientIdEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; @@ -49,9 +51,9 @@ public class MemberAuthServiceImpl implements MemberAuthService { @Resource private LoginLogApi loginLogApi; @Resource - private UserSessionApi userSessionApi; - @Resource private SocialUserApi socialUserApi; + @Resource + private OAuth2TokenApi oauth2TokenApi; @Resource private PasswordEncoder passwordEncoder; @@ -59,35 +61,31 @@ public class MemberAuthServiceImpl implements MemberAuthService { private MemberUserMapper userMapper; @Override - public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) { + public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) { // 使用手机 + 密码,进行登录。 - LoginUser loginUser = login0(reqVO.getMobile(), reqVO.getPassword()); + MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword()); - // 缓存登录用户到 Redis 中,返回 Token 令牌 - return createUserSessionAfterLoginSuccess(loginUser, reqVO.getMobile(), - LoginLogTypeEnum.LOGIN_USERNAME, userIp, userAgent); + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); } @Override @Transactional - public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { + public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) { // 校验验证码 + String userIp = getClientIP(); smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)); // 获得获得注册用户 MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); Assert.notNull(user, "获取用户失败,结果为空"); - // 执行登陆 - LoginUser loginUser = buildLoginUser(user); - - // 缓存登录用户到 Redis 中,返回 Token 令牌 - return createUserSessionAfterLoginSuccess(loginUser, reqVO.getMobile(), - LoginLogTypeEnum.LOGIN_SMS, userIp, userAgent); + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS); } @Override - public String socialQuickLogin(AppAuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent) { + public AppAuthLoginRespVO socialQuickLogin(AppAuthSocialQuickLoginReqVO reqVO) { // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 Long userId = socialUserApi.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), reqVO.getCode(), reqVO.getState()); @@ -101,33 +99,30 @@ public class MemberAuthServiceImpl implements MemberAuthService { throw exception(USER_NOT_EXISTS); } - // 创建 LoginUser 对象 - LoginUser loginUser = buildLoginUser(user); - - // 缓存登录用户到 Redis 中,返回 Token 令牌 - return createUserSessionAfterLoginSuccess(loginUser, null, - LoginLogTypeEnum.LOGIN_SOCIAL, userIp, userAgent); + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, null, LoginLogTypeEnum.LOGIN_SOCIAL); } @Override - public String socialBindLogin(AppAuthSocialBindLoginReqVO reqVO, String userIp, String userAgent) { + public AppAuthLoginRespVO socialBindLogin(AppAuthSocialBindLoginReqVO reqVO) { // 使用手机号、手机验证码登录 AppAuthSmsLoginReqVO loginReqVO = AppAuthSmsLoginReqVO.builder() .mobile(reqVO.getMobile()).code(reqVO.getSmsCode()).build(); - String token = this.smsLogin(loginReqVO, userIp, userAgent); - LoginUser loginUser = userSessionApi.getLoginUser(token); + AppAuthLoginRespVO token = smsLogin(loginReqVO); // 绑定社交用户 - socialUserApi.bindSocialUser(AuthConvert.INSTANCE.convert(loginUser.getId(), getUserType().getValue(), reqVO)); + socialUserApi.bindSocialUser(AuthConvert.INSTANCE.convert(token.getUserId(), getUserType().getValue(), reqVO)); return token; } - private String createUserSessionAfterLoginSuccess(LoginUser loginUser, String mobile, - LoginLogTypeEnum logType, String userIp, String userAgent) { + private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType) { // 插入登陆日志 - createLoginLog(loginUser.getId(), mobile, logType, LoginResultEnum.SUCCESS); - // 缓存登录用户到 Redis 中,返回 Token 令牌 - return userSessionApi.createUserSession(loginUser, userIp, userAgent); + createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); + // 创建 Token 令牌 + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO() + .setUserId(user.getId()).setUserType(getUserType().getValue()).setClientId(OAuth2ClientIdEnum.DEFAULT.getId())); + // 构建返回结果 + return AuthConvert.INSTANCE.convert(accessTokenRespDTO); } @Override @@ -135,7 +130,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { return socialUserApi.getAuthorizeUrl(type, redirectUri); } - private LoginUser login0(String mobile, String password) { + private MemberUserDO login0(String mobile, String password) { final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_MOBILE; // 校验账号是否存在 MemberUserDO user = userService.getUserByMobile(mobile); @@ -152,9 +147,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED); throw exception(AUTH_LOGIN_USER_DISABLED); } - - // 构建 User 对象 - return buildLoginUser(user); + return user; } private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) { @@ -177,15 +170,13 @@ public class MemberAuthServiceImpl implements MemberAuthService { @Override public void logout(String token) { - // 查询用户信息 - LoginUser loginUser = userSessionApi.getLoginUser(token); - if (loginUser == null) { + // 删除访问令牌 + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.removeAccessToken(token); + if (accessTokenRespDTO == null) { return; } - // 删除 session - userSessionApi.deleteUserSession(token); - // 记录登出日志 - createLogoutLog(loginUser.getId()); + // 删除成功,则记录登出日志 + createLogoutLog(accessTokenRespDTO.getUserId()); } @Override @@ -219,6 +210,12 @@ public class MemberAuthServiceImpl implements MemberAuthService { smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); } + @Override + public AppAuthLoginRespVO refreshToken(String refreshToken) { + OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, OAuth2ClientIdEnum.DEFAULT.getId()); + return AuthConvert.INSTANCE.convert(accessTokenDO); + } + /** * 校验旧密码 * @@ -260,10 +257,6 @@ public class MemberAuthServiceImpl implements MemberAuthService { loginLogApi.createLoginLog(reqDTO); } - private LoginUser buildLoginUser(MemberUserDO user) { - return AuthConvert.INSTANCE.convert(user).setUserType(getUserType().getValue()); - } - private String getMobile(Long userId) { if (userId == null) { return null; diff --git a/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java b/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java index a3a43b2d2..7218e6f1f 100644 --- a/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java +++ b/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthUpdatePasswo import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.service.user.MemberUserService; -import cn.iocoder.yudao.module.system.api.auth.UserSessionApi; +import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi; import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; import cn.iocoder.yudao.module.system.api.social.SocialUserApi; @@ -46,7 +46,7 @@ public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest { @MockBean private LoginLogApi loginLogApi; @MockBean - private UserSessionApi userSessionApi; + private OAuth2TokenApi oauth2TokenApi; @MockBean private SocialUserApi socialUserApi; @MockBean diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApi.java index 44c9079f5..ef82f5f53 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/OAuth2TokenApi.java @@ -13,10 +13,37 @@ import javax.validation.Valid; */ public interface OAuth2TokenApi { + /** + * 创建访问令牌 + * + * @param reqDTO 访问令牌的创建信息 + * @return 访问令牌的信息 + */ OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO); + /** + * 校验访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken); -// void removeToken(OAuth2RemoveTokenByUserReqDTO removeTokenDTO); + /** + * 移除访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenRespDTO removeAccessToken(String accessToken); + + /** + * 刷新访问令牌 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, Long clientId); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenCreateReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenCreateReqDTO.java index bf814f888..e9c5b953b 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenCreateReqDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenCreateReqDTO.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.api.auth.dto; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; import lombok.Data; -import lombok.experimental.Accessors; import javax.validation.constraints.NotNull; import java.io.Serializable; @@ -14,14 +13,13 @@ import java.io.Serializable; * @author 芋道源码 */ @Data -@Accessors(chain = true) public class OAuth2AccessTokenCreateReqDTO implements Serializable { /** * 用户编号 */ @NotNull(message = "用户编号不能为空") - private Integer userId; + private Long userId; /** * 用户类型 */ diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenRespDTO.java index 429fb071d..768955594 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenRespDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/auth/dto/OAuth2AccessTokenRespDTO.java @@ -26,7 +26,7 @@ public class OAuth2AccessTokenRespDTO implements Serializable { /** * 用户编号 */ - private Integer userId; + private Long userId; /** * 用户类型 */ 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 8a3cef022..80b7b1811 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 @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO 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 org.springframework.stereotype.Service; @@ -22,7 +23,9 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi { @Override public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) { - return null; + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken( + reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId()); + return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO); } @Override @@ -30,4 +33,16 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi { return OAuth2TokenConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken)); } + @Override + public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken); + return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO); + } + + @Override + public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, Long clientId) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId); + return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO); + } + } 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 1b626eac3..64cda89d7 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 @@ -11,6 +11,7 @@ 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; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; @@ -70,14 +71,15 @@ public class AuthController { public CommonResult logout(HttpServletRequest request) { String token = obtainAuthorization(request, securityProperties.getTokenHeader()); if (StrUtil.isNotBlank(token)) { - authService.logout(token); + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); } return success(true); } @PostMapping("/refresh-token") @ApiOperation("刷新令牌") - @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 TODO 接口文档 + @ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class) + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 public CommonResult refreshToken(@RequestParam("refreshToken") String refreshToken) { return success(authService.refreshToken(refreshToken)); } 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 new file mode 100644 index 000000000..042a873bd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java @@ -0,0 +1,50 @@ +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/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 new file mode 100644 index 000000000..77fbb0c4a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java @@ -0,0 +1,23 @@ +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 Long 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 new file mode 100644 index 000000000..4de251f93 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java @@ -0,0 +1,41 @@ +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 Long 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/OAuth2TokenConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java index 3bf96da32..882f69723 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 @@ -1,6 +1,9 @@ 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.dal.dataobject.auth.OAuth2AccessTokenDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -12,4 +15,8 @@ public interface OAuth2TokenConvert { OAuth2AccessTokenCheckRespDTO convert(OAuth2AccessTokenDO bean); + PageResult convert(PageResult page); + + OAuth2AccessTokenRespDTO convert2(OAuth2AccessTokenDO bean); + } 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 c31ca7ee8..6fadaf527 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 @@ -1,9 +1,13 @@ 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.dal.dataobject.auth.OAuth2AccessTokenDO; import org.apache.ibatis.annotations.Mapper; +import java.util.Date; import java.util.List; @Mapper @@ -17,4 +21,13 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX selectPage(OAuth2AccessTokenPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(OAuth2AccessTokenDO::getUserId, reqVO.getUserId()) + .eqIfPresent(OAuth2AccessTokenDO::getUserType, reqVO.getUserType()) + .eqIfPresent(OAuth2AccessTokenDO::getClientId, reqVO.getClientId()) + .gt(OAuth2AccessTokenDO::getExpiresTime, new Date()) + .orderByDesc(OAuth2AccessTokenDO::getId)); + } + } 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 3be7fdac1..5f67f9696 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 @@ -25,8 +25,9 @@ public interface AdminAuthService { * 基于 token 退出登录 * * @param token token + * @param logType 登出类型 */ - void logout(String token); + void logout(String token, Integer logType); /** * 短信验证码发送 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 92098b7ca..743c72aaa 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 @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; 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.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import com.google.common.annotations.VisibleForTesting; @@ -51,6 +52,8 @@ public class AdminAuthServiceImpl implements AdminAuthService { private OAuth2TokenService oauth2TokenService; @Resource private SocialUserService socialUserService; + @Resource + private MemberService memberService; @Resource private Validator validator; @@ -209,23 +212,27 @@ public class AdminAuthServiceImpl implements AdminAuthService { } @Override - public void logout(String token) { + public void logout(String token, Integer logType) { // 删除访问令牌 OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token); if (accessTokenDO == null) { return; } // 删除成功,则记录登出日志 - createLogoutLog(accessTokenDO.getUserId()); + createLogoutLog(accessTokenDO.getUserId(), accessTokenDO.getUserType(), logType); } - private void createLogoutLog(Long userId) { + private void createLogoutLog(Long userId, Integer userType, Integer logType) { LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); - reqDTO.setLogType(LoginLogTypeEnum.LOGOUT_SELF.getType()); + reqDTO.setLogType(logType); reqDTO.setTraceId(TracerUtils.getTraceId()); reqDTO.setUserId(userId); - reqDTO.setUsername(getUsername(userId)); - reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUserType(userType); + if (ObjectUtil.notEqual(getUserType(), userType)) { + reqDTO.setUsername(getUsername(userId)); + } else { + reqDTO.setUsername(memberService.getMemberUserMobile(userId)); + } reqDTO.setUserAgent(ServletUtils.getUserAgent()); reqDTO.setUserIp(ServletUtils.getClientIP()); reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); 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 index 20134fa0b..541d2c7c7 100644 --- 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 @@ -1,5 +1,7 @@ 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; /** @@ -64,4 +66,12 @@ public interface OAuth2TokenService { */ 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 index 609a3b0d7..f8d824690 100644 --- 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 @@ -4,8 +4,10 @@ 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; @@ -125,6 +127,11 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { 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.getId()) 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 b8441d111..7355c4d77 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 @@ -221,7 +221,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest { when(oauth2TokenService.removeAccessToken(eq(token))).thenReturn(accessTokenDO); // 调用 - authService.logout(token); + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); // 校验调用参数 verify(loginLogService).createLoginLog(argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) @@ -234,7 +234,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest { String token = randomString(); // 调用 - authService.logout(token); + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); // 校验调用参数 verify(loginLogService, never()).createLoginLog(any()); } diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index e243290d5..4480f88a5 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -21,11 +21,11 @@ https://github.com/YunaiV/ruoyi-vue-pro - - - - - + + cn.iocoder.boot + yudao-module-member-biz + ${revision} + cn.iocoder.boot yudao-module-system-biz diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 144c8d92f..f840f8a42 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -173,8 +173,6 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta yudao: security: token-header: Authorization - token-timeout: 1d - session-timeout: 30m mock-enable: true mock-secret: test xss: diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 21476090f..d1d854da9 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -193,8 +193,6 @@ yudao: enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试 security: token-header: Authorization - token-timeout: 1d - session-timeout: 1d mock-enable: true mock-secret: test xss: diff --git a/yudao-ui-admin/src/api/system/oauth2/oauth2Token.js b/yudao-ui-admin/src/api/system/oauth2/oauth2Token.js new file mode 100644 index 000000000..37402e8f0 --- /dev/null +++ b/yudao-ui-admin/src/api/system/oauth2/oauth2Token.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 获得访问令牌分页 +export function getAccessTokenPage(query) { + return request({ + url: '/system/oauth2-token/page', + method: 'get', + params: query + }) +} + +// 删除访问令牌 +export function deleteAccessToken(accessToken) { + return request({ + url: '/system/oauth2-token/delete?accessToken=' + accessToken, + method: 'delete' + }) +} diff --git a/yudao-ui-admin/src/api/system/session.js b/yudao-ui-admin/src/api/system/session.js deleted file mode 100644 index dee070995..000000000 --- a/yudao-ui-admin/src/api/system/session.js +++ /dev/null @@ -1,18 +0,0 @@ -import request from '@/utils/request' - -// 查询在线用户列表 -export function list(query) { - return request({ - url: '/system/user-session/page', - method: 'get', - params: query - }) -} - -// 强退用户 -export function forceLogout(tokenId) { - return request({ - url: '/system/user-session/delete?id=' + tokenId, - method: 'delete' - }) -} diff --git a/yudao-ui-admin/src/views/system/session/index.vue b/yudao-ui-admin/src/views/system/oauth2/token/index.vue similarity index 55% rename from yudao-ui-admin/src/views/system/session/index.vue rename to yudao-ui-admin/src/views/system/oauth2/token/index.vue index 10135403c..a6cb9131c 100644 --- a/yudao-ui-admin/src/views/system/session/index.vue +++ b/yudao-ui-admin/src/views/system/oauth2/token/index.vue @@ -3,11 +3,14 @@ - - + + - - + + + + 搜索 @@ -16,20 +19,28 @@ - - - - - - + + + + + + + + + + @@ -40,10 +51,10 @@