Commit 5cf68961e1a5d7b310e6e9d8b9308c88c254b0dd
1 parent
6ed62486
1. 修改在线会话的实现
2. 接入到会员管理 OAuth2.0
Showing
28 changed files
with
356 additions
and
150 deletions
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; | @@ -6,7 +6,6 @@ import org.springframework.validation.annotation.Validated; | ||
| 6 | 6 | ||
| 7 | import javax.validation.constraints.NotEmpty; | 7 | import javax.validation.constraints.NotEmpty; |
| 8 | import javax.validation.constraints.NotNull; | 8 | import javax.validation.constraints.NotNull; |
| 9 | -import java.time.Duration; | ||
| 10 | 9 | ||
| 11 | @ConfigurationProperties(prefix = "yudao.security") | 10 | @ConfigurationProperties(prefix = "yudao.security") |
| 12 | @Validated | 11 | @Validated |
| @@ -18,18 +17,6 @@ public class SecurityProperties { | @@ -18,18 +17,6 @@ public class SecurityProperties { | ||
| 18 | */ | 17 | */ |
| 19 | @NotEmpty(message = "Token Header 不能为空") | 18 | @NotEmpty(message = "Token Header 不能为空") |
| 20 | private String tokenHeader; | 19 | private String tokenHeader; |
| 21 | - /** | ||
| 22 | - * Token 过期时间 | ||
| 23 | - */ | ||
| 24 | - @NotNull(message = "Token 过期时间不能为空") | ||
| 25 | - private Duration tokenTimeout; | ||
| 26 | - /** | ||
| 27 | - * Session 过期时间 | ||
| 28 | - * | ||
| 29 | - * 当 User 用户超过当前时间未操作,则 Session 会过期 | ||
| 30 | - */ | ||
| 31 | - @NotNull(message = "Session 过期时间不能为空") | ||
| 32 | - private Duration sessionTimeout; | ||
| 33 | 20 | ||
| 34 | /** | 21 | /** |
| 35 | * mock 模式的开关 | 22 | * mock 模式的开关 |
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}} | @@ -19,7 +19,7 @@ tenant-id: {{appTenentId}} | ||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | ### 请求 /sms-login 接口 => 成功 | 21 | ### 请求 /sms-login 接口 => 成功 |
| 22 | -POST {{appApi}}/member/sms-login | 22 | +POST {{appApi}}/member/auth/sms-login |
| 23 | Content-Type: application/json | 23 | Content-Type: application/json |
| 24 | tenant-id: {{appTenentId}} | 24 | tenant-id: {{appTenentId}} |
| 25 | 25 | ||
| @@ -29,7 +29,12 @@ tenant-id: {{appTenentId}} | @@ -29,7 +29,12 @@ tenant-id: {{appTenentId}} | ||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | ### 请求 /logout 接口 => 成功 | 31 | ### 请求 /logout 接口 => 成功 |
| 32 | -POST {{appApi}}/member/logout | 32 | +POST {{appApi}}/member/auth/logout |
| 33 | Content-Type: application/json | 33 | Content-Type: application/json |
| 34 | Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 | 34 | Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 |
| 35 | tenant-id: {{appTenentId}} | 35 | tenant-id: {{appTenentId}} |
| 36 | + | ||
| 37 | +### 请求 /auth/refresh-token 接口 => 成功 | ||
| 38 | +POST {{appApi}}/member/auth/refresh-token?refreshToken=bc43d929094849a28b3a69f6e6940d70 | ||
| 39 | +Content-Type: application/json | ||
| 40 | +tenant-id: {{appTenentId}} |
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; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.StrUtil; | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||
| 5 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; | 6 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | 7 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 7 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| @@ -20,8 +21,6 @@ import javax.servlet.http.HttpServletRequest; | @@ -20,8 +21,6 @@ import javax.servlet.http.HttpServletRequest; | ||
| 20 | import javax.validation.Valid; | 21 | import javax.validation.Valid; |
| 21 | 22 | ||
| 22 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 23 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 23 | -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||
| 24 | -import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent; | ||
| 25 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 24 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 26 | 25 | ||
| 27 | @Api(tags = "用户 APP - 认证") | 26 | @Api(tags = "用户 APP - 认证") |
| @@ -40,8 +39,7 @@ public class AppAuthController { | @@ -40,8 +39,7 @@ public class AppAuthController { | ||
| 40 | @PostMapping("/login") | 39 | @PostMapping("/login") |
| 41 | @ApiOperation("使用手机 + 密码登录") | 40 | @ApiOperation("使用手机 + 密码登录") |
| 42 | public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { | 41 | public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { |
| 43 | - String token = authService.login(reqVO, getClientIP(), getUserAgent()); | ||
| 44 | - return success(AppAuthLoginRespVO.builder().token(token).build()); | 42 | + return success(authService.login(reqVO)); |
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | @PostMapping("/logout") | 45 | @PostMapping("/logout") |
| @@ -54,12 +52,20 @@ public class AppAuthController { | @@ -54,12 +52,20 @@ public class AppAuthController { | ||
| 54 | return success(true); | 52 | return success(true); |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 55 | + @PostMapping("/refresh-token") | ||
| 56 | + @ApiOperation("刷新令牌") | ||
| 57 | + @ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class) | ||
| 58 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 59 | + public CommonResult<AppAuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) { | ||
| 60 | + return success(authService.refreshToken(refreshToken)); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // ========== 短信登录相关 ========== | ||
| 64 | + | ||
| 57 | @PostMapping("/sms-login") | 65 | @PostMapping("/sms-login") |
| 58 | @ApiOperation("使用手机 + 验证码登录") | 66 | @ApiOperation("使用手机 + 验证码登录") |
| 59 | public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { | 67 | public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { |
| 60 | - String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent()); | ||
| 61 | - // 返回结果 | ||
| 62 | - return success(AppAuthLoginRespVO.builder().token(token).build()); | 68 | + return success(authService.smsLogin(reqVO)); |
| 63 | } | 69 | } |
| 64 | 70 | ||
| 65 | @PostMapping("/send-sms-code") | 71 | @PostMapping("/send-sms-code") |
| @@ -100,16 +106,14 @@ public class AppAuthController { | @@ -100,16 +106,14 @@ public class AppAuthController { | ||
| 100 | 106 | ||
| 101 | @PostMapping("/social-quick-login") | 107 | @PostMapping("/social-quick-login") |
| 102 | @ApiOperation(value = "社交快捷登录,使用 code 授权码", notes = "适合未登录的用户,但是社交账号已绑定用户") | 108 | @ApiOperation(value = "社交快捷登录,使用 code 授权码", notes = "适合未登录的用户,但是社交账号已绑定用户") |
| 103 | - public CommonResult<AppAuthLoginRespVO> socialLogin(@RequestBody @Valid AppAuthSocialQuickLoginReqVO reqVO) { | ||
| 104 | - String token = authService.socialQuickLogin(reqVO, getClientIP(), getUserAgent()); | ||
| 105 | - return success(AppAuthLoginRespVO.builder().token(token).build()); | 109 | + public CommonResult<AppAuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AppAuthSocialQuickLoginReqVO reqVO) { |
| 110 | + return success(authService.socialQuickLogin(reqVO)); | ||
| 106 | } | 111 | } |
| 107 | 112 | ||
| 108 | @PostMapping("/social-bind-login") | 113 | @PostMapping("/social-bind-login") |
| 109 | @ApiOperation(value = "社交绑定登录,使用 手机号 + 手机验证码", notes = "适合未登录的用户,进行登录 + 绑定") | 114 | @ApiOperation(value = "社交绑定登录,使用 手机号 + 手机验证码", notes = "适合未登录的用户,进行登录 + 绑定") |
| 110 | - public CommonResult<AppAuthLoginRespVO> socialLogin2(@RequestBody @Valid AppAuthSocialBindLoginReqVO reqVO) { | ||
| 111 | - String token = authService.socialBindLogin(reqVO, getClientIP(), getUserAgent()); | ||
| 112 | - return success(AppAuthLoginRespVO.builder().token(token).build()); | 115 | + public CommonResult<AppAuthLoginRespVO> socialBindLogin(@RequestBody @Valid AppAuthSocialBindLoginReqVO reqVO) { |
| 116 | + return success(authService.socialBindLogin(reqVO)); | ||
| 113 | } | 117 | } |
| 114 | 118 | ||
| 115 | } | 119 | } |
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; | @@ -7,14 +7,25 @@ import lombok.Builder; | ||
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 9 | 9 | ||
| 10 | -@ApiModel("用户 APP - 手机密码登录 Response VO") | 10 | +import java.util.Date; |
| 11 | + | ||
| 12 | +@ApiModel("用户 APP - 登录 Response VO") | ||
| 11 | @Data | 13 | @Data |
| 12 | @NoArgsConstructor | 14 | @NoArgsConstructor |
| 13 | @AllArgsConstructor | 15 | @AllArgsConstructor |
| 14 | @Builder | 16 | @Builder |
| 15 | public class AppAuthLoginRespVO { | 17 | public class AppAuthLoginRespVO { |
| 16 | 18 | ||
| 17 | - @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma") | ||
| 18 | - private String token; | 19 | + @ApiModelProperty(value = "用户编号", required = true, example = "1024") |
| 20 | + private Long userId; | ||
| 21 | + | ||
| 22 | + @ApiModelProperty(value = "访问令牌", required = true, example = "happy") | ||
| 23 | + private String accessToken; | ||
| 24 | + | ||
| 25 | + @ApiModelProperty(value = "刷新令牌", required = true, example = "nice") | ||
| 26 | + private String refreshToken; | ||
| 27 | + | ||
| 28 | + @ApiModelProperty(value = "过期时间", required = true) | ||
| 29 | + private Date expiresTime; | ||
| 19 | 30 | ||
| 20 | } | 31 | } |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java
| 1 | package cn.iocoder.yudao.module.member.convert.auth; | 1 | package cn.iocoder.yudao.module.member.convert.auth; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 4 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; | 3 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; |
| 5 | import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; | 4 | import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; |
| 6 | -import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; | 5 | +import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; |
| 7 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; | 6 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; |
| 8 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; | 7 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; |
| 9 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; | 8 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| @@ -17,8 +16,6 @@ public interface AuthConvert { | @@ -17,8 +16,6 @@ public interface AuthConvert { | ||
| 17 | 16 | ||
| 18 | AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); | 17 | AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); |
| 19 | 18 | ||
| 20 | - LoginUser convert(MemberUserDO bean); | ||
| 21 | - | ||
| 22 | SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialBindLoginReqVO reqVO); | 19 | SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialBindLoginReqVO reqVO); |
| 23 | SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialQuickLoginReqVO reqVO); | 20 | SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialQuickLoginReqVO reqVO); |
| 24 | SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppSocialUserUnbindReqVO reqVO); | 21 | SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppSocialUserUnbindReqVO reqVO); |
| @@ -27,4 +24,6 @@ public interface AuthConvert { | @@ -27,4 +24,6 @@ public interface AuthConvert { | ||
| 27 | SmsCodeUseReqDTO convert(AppAuthResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); | 24 | SmsCodeUseReqDTO convert(AppAuthResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); |
| 28 | SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); | 25 | SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); |
| 29 | 26 | ||
| 27 | + AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean); | ||
| 28 | + | ||
| 30 | } | 29 | } |
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 { | @@ -17,11 +17,9 @@ public interface MemberAuthService { | ||
| 17 | * 手机 + 密码登录 | 17 | * 手机 + 密码登录 |
| 18 | * | 18 | * |
| 19 | * @param reqVO 登录信息 | 19 | * @param reqVO 登录信息 |
| 20 | - * @param userIp 用户 IP | ||
| 21 | - * @param userAgent 用户 UA | ||
| 22 | - * @return 身份令牌,使用 JWT 方式 | 20 | + * @return 登录结果 |
| 23 | */ | 21 | */ |
| 24 | - String login(@Valid AppAuthLoginReqVO reqVO, String userIp, String userAgent); | 22 | + AppAuthLoginRespVO login(@Valid AppAuthLoginReqVO reqVO); |
| 25 | 23 | ||
| 26 | /** | 24 | /** |
| 27 | * 基于 token 退出登录 | 25 | * 基于 token 退出登录 |
| @@ -34,31 +32,25 @@ public interface MemberAuthService { | @@ -34,31 +32,25 @@ public interface MemberAuthService { | ||
| 34 | * 手机 + 验证码登陆 | 32 | * 手机 + 验证码登陆 |
| 35 | * | 33 | * |
| 36 | * @param reqVO 登陆信息 | 34 | * @param reqVO 登陆信息 |
| 37 | - * @param userIp 用户 IP | ||
| 38 | - * @param userAgent 用户 UA | ||
| 39 | - * @return 身份令牌,使用 JWT 方式 | 35 | + * @return 登录结果 |
| 40 | */ | 36 | */ |
| 41 | - String smsLogin(@Valid AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent); | 37 | + AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO); |
| 42 | 38 | ||
| 43 | /** | 39 | /** |
| 44 | * 社交登录,使用 code 授权码 | 40 | * 社交登录,使用 code 授权码 |
| 45 | * | 41 | * |
| 46 | * @param reqVO 登录信息 | 42 | * @param reqVO 登录信息 |
| 47 | - * @param userIp 用户 IP | ||
| 48 | - * @param userAgent 用户 UA | ||
| 49 | - * @return 身份令牌,使用 JWT 方式 | 43 | + * @return 登录结果 |
| 50 | */ | 44 | */ |
| 51 | - String socialQuickLogin(@Valid AppAuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent); | 45 | + AppAuthLoginRespVO socialQuickLogin(@Valid AppAuthSocialQuickLoginReqVO reqVO); |
| 52 | 46 | ||
| 53 | /** | 47 | /** |
| 54 | * 社交登录,使用 手机号 + 手机验证码 | 48 | * 社交登录,使用 手机号 + 手机验证码 |
| 55 | * | 49 | * |
| 56 | * @param reqVO 登录信息 | 50 | * @param reqVO 登录信息 |
| 57 | - * @param userIp 用户 IP | ||
| 58 | - * @param userAgent 用户 UA | ||
| 59 | - * @return 身份令牌,使用 JWT 方式 | 51 | + * @return 登录结果 |
| 60 | */ | 52 | */ |
| 61 | - String socialBindLogin(@Valid AppAuthSocialBindLoginReqVO reqVO, String userIp, String userAgent); | 53 | + AppAuthLoginRespVO socialBindLogin(@Valid AppAuthSocialBindLoginReqVO reqVO); |
| 62 | 54 | ||
| 63 | /** | 55 | /** |
| 64 | * 获得社交认证 URL | 56 | * 获得社交认证 URL |
| @@ -90,4 +82,11 @@ public interface MemberAuthService { | @@ -90,4 +82,11 @@ public interface MemberAuthService { | ||
| 90 | */ | 82 | */ |
| 91 | void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO); | 83 | void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO); |
| 92 | 84 | ||
| 85 | + /** | ||
| 86 | + * 刷新访问令牌 | ||
| 87 | + * | ||
| 88 | + * @param refreshToken 刷新令牌 | ||
| 89 | + * @return 登录结果 | ||
| 90 | + */ | ||
| 91 | + AppAuthLoginRespVO refreshToken(String refreshToken); | ||
| 93 | } | 92 | } |
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; | @@ -6,17 +6,19 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 7 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | 7 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; |
| 8 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 8 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 9 | -import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 10 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; | 9 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; |
| 11 | import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; | 10 | import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; |
| 12 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; | 11 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
| 13 | import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; | 12 | import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; |
| 14 | import cn.iocoder.yudao.module.member.service.user.MemberUserService; | 13 | import cn.iocoder.yudao.module.member.service.user.MemberUserService; |
| 15 | -import cn.iocoder.yudao.module.system.api.auth.UserSessionApi; | 14 | +import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi; |
| 15 | +import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO; | ||
| 16 | +import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; | ||
| 16 | import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; | 17 | import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; |
| 17 | import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; | 18 | import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; |
| 18 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; | 19 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 19 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; | 20 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; |
| 21 | +import cn.iocoder.yudao.module.system.enums.auth.OAuth2ClientIdEnum; | ||
| 20 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; | 22 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; |
| 21 | import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; | 23 | import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; |
| 22 | import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; | 24 | import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; |
| @@ -49,9 +51,9 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -49,9 +51,9 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 49 | @Resource | 51 | @Resource |
| 50 | private LoginLogApi loginLogApi; | 52 | private LoginLogApi loginLogApi; |
| 51 | @Resource | 53 | @Resource |
| 52 | - private UserSessionApi userSessionApi; | ||
| 53 | - @Resource | ||
| 54 | private SocialUserApi socialUserApi; | 54 | private SocialUserApi socialUserApi; |
| 55 | + @Resource | ||
| 56 | + private OAuth2TokenApi oauth2TokenApi; | ||
| 55 | 57 | ||
| 56 | @Resource | 58 | @Resource |
| 57 | private PasswordEncoder passwordEncoder; | 59 | private PasswordEncoder passwordEncoder; |
| @@ -59,35 +61,31 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -59,35 +61,31 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 59 | private MemberUserMapper userMapper; | 61 | private MemberUserMapper userMapper; |
| 60 | 62 | ||
| 61 | @Override | 63 | @Override |
| 62 | - public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) { | 64 | + public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) { |
| 63 | // 使用手机 + 密码,进行登录。 | 65 | // 使用手机 + 密码,进行登录。 |
| 64 | - LoginUser loginUser = login0(reqVO.getMobile(), reqVO.getPassword()); | 66 | + MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword()); |
| 65 | 67 | ||
| 66 | - // 缓存登录用户到 Redis 中,返回 Token 令牌 | ||
| 67 | - return createUserSessionAfterLoginSuccess(loginUser, reqVO.getMobile(), | ||
| 68 | - LoginLogTypeEnum.LOGIN_USERNAME, userIp, userAgent); | 68 | + // 创建 Token 令牌,记录登录日志 |
| 69 | + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); | ||
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | @Override | 72 | @Override |
| 72 | @Transactional | 73 | @Transactional |
| 73 | - public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { | 74 | + public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) { |
| 74 | // 校验验证码 | 75 | // 校验验证码 |
| 76 | + String userIp = getClientIP(); | ||
| 75 | smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)); | 77 | smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)); |
| 76 | 78 | ||
| 77 | // 获得获得注册用户 | 79 | // 获得获得注册用户 |
| 78 | MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); | 80 | MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); |
| 79 | Assert.notNull(user, "获取用户失败,结果为空"); | 81 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 80 | 82 | ||
| 81 | - // 执行登陆 | ||
| 82 | - LoginUser loginUser = buildLoginUser(user); | ||
| 83 | - | ||
| 84 | - // 缓存登录用户到 Redis 中,返回 Token 令牌 | ||
| 85 | - return createUserSessionAfterLoginSuccess(loginUser, reqVO.getMobile(), | ||
| 86 | - LoginLogTypeEnum.LOGIN_SMS, userIp, userAgent); | 83 | + // 创建 Token 令牌,记录登录日志 |
| 84 | + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS); | ||
| 87 | } | 85 | } |
| 88 | 86 | ||
| 89 | @Override | 87 | @Override |
| 90 | - public String socialQuickLogin(AppAuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent) { | 88 | + public AppAuthLoginRespVO socialQuickLogin(AppAuthSocialQuickLoginReqVO reqVO) { |
| 91 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 | 89 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 92 | Long userId = socialUserApi.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), | 90 | Long userId = socialUserApi.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), |
| 93 | reqVO.getCode(), reqVO.getState()); | 91 | reqVO.getCode(), reqVO.getState()); |
| @@ -101,33 +99,30 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -101,33 +99,30 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 101 | throw exception(USER_NOT_EXISTS); | 99 | throw exception(USER_NOT_EXISTS); |
| 102 | } | 100 | } |
| 103 | 101 | ||
| 104 | - // 创建 LoginUser 对象 | ||
| 105 | - LoginUser loginUser = buildLoginUser(user); | ||
| 106 | - | ||
| 107 | - // 缓存登录用户到 Redis 中,返回 Token 令牌 | ||
| 108 | - return createUserSessionAfterLoginSuccess(loginUser, null, | ||
| 109 | - LoginLogTypeEnum.LOGIN_SOCIAL, userIp, userAgent); | 102 | + // 创建 Token 令牌,记录登录日志 |
| 103 | + return createTokenAfterLoginSuccess(user, null, LoginLogTypeEnum.LOGIN_SOCIAL); | ||
| 110 | } | 104 | } |
| 111 | 105 | ||
| 112 | @Override | 106 | @Override |
| 113 | - public String socialBindLogin(AppAuthSocialBindLoginReqVO reqVO, String userIp, String userAgent) { | 107 | + public AppAuthLoginRespVO socialBindLogin(AppAuthSocialBindLoginReqVO reqVO) { |
| 114 | // 使用手机号、手机验证码登录 | 108 | // 使用手机号、手机验证码登录 |
| 115 | AppAuthSmsLoginReqVO loginReqVO = AppAuthSmsLoginReqVO.builder() | 109 | AppAuthSmsLoginReqVO loginReqVO = AppAuthSmsLoginReqVO.builder() |
| 116 | .mobile(reqVO.getMobile()).code(reqVO.getSmsCode()).build(); | 110 | .mobile(reqVO.getMobile()).code(reqVO.getSmsCode()).build(); |
| 117 | - String token = this.smsLogin(loginReqVO, userIp, userAgent); | ||
| 118 | - LoginUser loginUser = userSessionApi.getLoginUser(token); | 111 | + AppAuthLoginRespVO token = smsLogin(loginReqVO); |
| 119 | 112 | ||
| 120 | // 绑定社交用户 | 113 | // 绑定社交用户 |
| 121 | - socialUserApi.bindSocialUser(AuthConvert.INSTANCE.convert(loginUser.getId(), getUserType().getValue(), reqVO)); | 114 | + socialUserApi.bindSocialUser(AuthConvert.INSTANCE.convert(token.getUserId(), getUserType().getValue(), reqVO)); |
| 122 | return token; | 115 | return token; |
| 123 | } | 116 | } |
| 124 | 117 | ||
| 125 | - private String createUserSessionAfterLoginSuccess(LoginUser loginUser, String mobile, | ||
| 126 | - LoginLogTypeEnum logType, String userIp, String userAgent) { | 118 | + private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType) { |
| 127 | // 插入登陆日志 | 119 | // 插入登陆日志 |
| 128 | - createLoginLog(loginUser.getId(), mobile, logType, LoginResultEnum.SUCCESS); | ||
| 129 | - // 缓存登录用户到 Redis 中,返回 Token 令牌 | ||
| 130 | - return userSessionApi.createUserSession(loginUser, userIp, userAgent); | 120 | + createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); |
| 121 | + // 创建 Token 令牌 | ||
| 122 | + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO() | ||
| 123 | + .setUserId(user.getId()).setUserType(getUserType().getValue()).setClientId(OAuth2ClientIdEnum.DEFAULT.getId())); | ||
| 124 | + // 构建返回结果 | ||
| 125 | + return AuthConvert.INSTANCE.convert(accessTokenRespDTO); | ||
| 131 | } | 126 | } |
| 132 | 127 | ||
| 133 | @Override | 128 | @Override |
| @@ -135,7 +130,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -135,7 +130,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 135 | return socialUserApi.getAuthorizeUrl(type, redirectUri); | 130 | return socialUserApi.getAuthorizeUrl(type, redirectUri); |
| 136 | } | 131 | } |
| 137 | 132 | ||
| 138 | - private LoginUser login0(String mobile, String password) { | 133 | + private MemberUserDO login0(String mobile, String password) { |
| 139 | final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_MOBILE; | 134 | final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_MOBILE; |
| 140 | // 校验账号是否存在 | 135 | // 校验账号是否存在 |
| 141 | MemberUserDO user = userService.getUserByMobile(mobile); | 136 | MemberUserDO user = userService.getUserByMobile(mobile); |
| @@ -152,9 +147,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -152,9 +147,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 152 | createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED); | 147 | createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED); |
| 153 | throw exception(AUTH_LOGIN_USER_DISABLED); | 148 | throw exception(AUTH_LOGIN_USER_DISABLED); |
| 154 | } | 149 | } |
| 155 | - | ||
| 156 | - // 构建 User 对象 | ||
| 157 | - return buildLoginUser(user); | 150 | + return user; |
| 158 | } | 151 | } |
| 159 | 152 | ||
| 160 | private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) { | 153 | private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) { |
| @@ -177,15 +170,13 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -177,15 +170,13 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 177 | 170 | ||
| 178 | @Override | 171 | @Override |
| 179 | public void logout(String token) { | 172 | public void logout(String token) { |
| 180 | - // 查询用户信息 | ||
| 181 | - LoginUser loginUser = userSessionApi.getLoginUser(token); | ||
| 182 | - if (loginUser == null) { | 173 | + // 删除访问令牌 |
| 174 | + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.removeAccessToken(token); | ||
| 175 | + if (accessTokenRespDTO == null) { | ||
| 183 | return; | 176 | return; |
| 184 | } | 177 | } |
| 185 | - // 删除 session | ||
| 186 | - userSessionApi.deleteUserSession(token); | ||
| 187 | - // 记录登出日志 | ||
| 188 | - createLogoutLog(loginUser.getId()); | 178 | + // 删除成功,则记录登出日志 |
| 179 | + createLogoutLog(accessTokenRespDTO.getUserId()); | ||
| 189 | } | 180 | } |
| 190 | 181 | ||
| 191 | @Override | 182 | @Override |
| @@ -219,6 +210,12 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -219,6 +210,12 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 219 | smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); | 210 | smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); |
| 220 | } | 211 | } |
| 221 | 212 | ||
| 213 | + @Override | ||
| 214 | + public AppAuthLoginRespVO refreshToken(String refreshToken) { | ||
| 215 | + OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, OAuth2ClientIdEnum.DEFAULT.getId()); | ||
| 216 | + return AuthConvert.INSTANCE.convert(accessTokenDO); | ||
| 217 | + } | ||
| 218 | + | ||
| 222 | /** | 219 | /** |
| 223 | * 校验旧密码 | 220 | * 校验旧密码 |
| 224 | * | 221 | * |
| @@ -260,10 +257,6 @@ public class MemberAuthServiceImpl implements MemberAuthService { | @@ -260,10 +257,6 @@ public class MemberAuthServiceImpl implements MemberAuthService { | ||
| 260 | loginLogApi.createLoginLog(reqDTO); | 257 | loginLogApi.createLoginLog(reqDTO); |
| 261 | } | 258 | } |
| 262 | 259 | ||
| 263 | - private LoginUser buildLoginUser(MemberUserDO user) { | ||
| 264 | - return AuthConvert.INSTANCE.convert(user).setUserType(getUserType().getValue()); | ||
| 265 | - } | ||
| 266 | - | ||
| 267 | private String getMobile(Long userId) { | 260 | private String getMobile(Long userId) { |
| 268 | if (userId == null) { | 261 | if (userId == null) { |
| 269 | return null; | 262 | return null; |
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 | @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthUpdatePasswo | ||
| 9 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; | 9 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
| 10 | import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; | 10 | import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; |
| 11 | import cn.iocoder.yudao.module.member.service.user.MemberUserService; | 11 | import cn.iocoder.yudao.module.member.service.user.MemberUserService; |
| 12 | -import cn.iocoder.yudao.module.system.api.auth.UserSessionApi; | 12 | +import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi; |
| 13 | import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; | 13 | import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; |
| 14 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; | 14 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 15 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; | 15 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; |
| @@ -46,7 +46,7 @@ public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest { | @@ -46,7 +46,7 @@ public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest { | ||
| 46 | @MockBean | 46 | @MockBean |
| 47 | private LoginLogApi loginLogApi; | 47 | private LoginLogApi loginLogApi; |
| 48 | @MockBean | 48 | @MockBean |
| 49 | - private UserSessionApi userSessionApi; | 49 | + private OAuth2TokenApi oauth2TokenApi; |
| 50 | @MockBean | 50 | @MockBean |
| 51 | private SocialUserApi socialUserApi; | 51 | private SocialUserApi socialUserApi; |
| 52 | @MockBean | 52 | @MockBean |
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; | @@ -13,10 +13,37 @@ import javax.validation.Valid; | ||
| 13 | */ | 13 | */ |
| 14 | public interface OAuth2TokenApi { | 14 | public interface OAuth2TokenApi { |
| 15 | 15 | ||
| 16 | + /** | ||
| 17 | + * 创建访问令牌 | ||
| 18 | + * | ||
| 19 | + * @param reqDTO 访问令牌的创建信息 | ||
| 20 | + * @return 访问令牌的信息 | ||
| 21 | + */ | ||
| 16 | OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO); | 22 | OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO); |
| 17 | 23 | ||
| 24 | + /** | ||
| 25 | + * 校验访问令牌 | ||
| 26 | + * | ||
| 27 | + * @param accessToken 访问令牌 | ||
| 28 | + * @return 访问令牌的信息 | ||
| 29 | + */ | ||
| 18 | OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken); | 30 | OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken); |
| 19 | 31 | ||
| 20 | -// void removeToken(OAuth2RemoveTokenByUserReqDTO removeTokenDTO); | 32 | + /** |
| 33 | + * 移除访问令牌 | ||
| 34 | + * | ||
| 35 | + * @param accessToken 访问令牌 | ||
| 36 | + * @return 访问令牌的信息 | ||
| 37 | + */ | ||
| 38 | + OAuth2AccessTokenRespDTO removeAccessToken(String accessToken); | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 刷新访问令牌 | ||
| 42 | + * | ||
| 43 | + * @param refreshToken 刷新令牌 | ||
| 44 | + * @param clientId 客户端编号 | ||
| 45 | + * @return 访问令牌的信息 | ||
| 46 | + */ | ||
| 47 | + OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, Long clientId); | ||
| 21 | 48 | ||
| 22 | } | 49 | } |
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; | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.api.auth.dto; | ||
| 3 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | -import lombok.experimental.Accessors; | ||
| 7 | 6 | ||
| 8 | import javax.validation.constraints.NotNull; | 7 | import javax.validation.constraints.NotNull; |
| 9 | import java.io.Serializable; | 8 | import java.io.Serializable; |
| @@ -14,14 +13,13 @@ import java.io.Serializable; | @@ -14,14 +13,13 @@ import java.io.Serializable; | ||
| 14 | * @author 芋道源码 | 13 | * @author 芋道源码 |
| 15 | */ | 14 | */ |
| 16 | @Data | 15 | @Data |
| 17 | -@Accessors(chain = true) | ||
| 18 | public class OAuth2AccessTokenCreateReqDTO implements Serializable { | 16 | public class OAuth2AccessTokenCreateReqDTO implements Serializable { |
| 19 | 17 | ||
| 20 | /** | 18 | /** |
| 21 | * 用户编号 | 19 | * 用户编号 |
| 22 | */ | 20 | */ |
| 23 | @NotNull(message = "用户编号不能为空") | 21 | @NotNull(message = "用户编号不能为空") |
| 24 | - private Integer userId; | 22 | + private Long userId; |
| 25 | /** | 23 | /** |
| 26 | * 用户类型 | 24 | * 用户类型 |
| 27 | */ | 25 | */ |
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 { | @@ -26,7 +26,7 @@ public class OAuth2AccessTokenRespDTO implements Serializable { | ||
| 26 | /** | 26 | /** |
| 27 | * 用户编号 | 27 | * 用户编号 |
| 28 | */ | 28 | */ |
| 29 | - private Integer userId; | 29 | + private Long userId; |
| 30 | /** | 30 | /** |
| 31 | * 用户类型 | 31 | * 用户类型 |
| 32 | */ | 32 | */ |
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 | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO | ||
| 4 | import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO; | 4 | import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO; |
| 5 | import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; | 5 | import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; |
| 6 | import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert; | 6 | import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert; |
| 7 | +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | ||
| 7 | import cn.iocoder.yudao.module.system.service.auth.OAuth2TokenService; | 8 | import cn.iocoder.yudao.module.system.service.auth.OAuth2TokenService; |
| 8 | import org.springframework.stereotype.Service; | 9 | import org.springframework.stereotype.Service; |
| 9 | 10 | ||
| @@ -22,7 +23,9 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi { | @@ -22,7 +23,9 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi { | ||
| 22 | 23 | ||
| 23 | @Override | 24 | @Override |
| 24 | public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) { | 25 | public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) { |
| 25 | - return null; | 26 | + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken( |
| 27 | + reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId()); | ||
| 28 | + return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO); | ||
| 26 | } | 29 | } |
| 27 | 30 | ||
| 28 | @Override | 31 | @Override |
| @@ -30,4 +33,16 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi { | @@ -30,4 +33,16 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi { | ||
| 30 | return OAuth2TokenConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken)); | 33 | return OAuth2TokenConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken)); |
| 31 | } | 34 | } |
| 32 | 35 | ||
| 36 | + @Override | ||
| 37 | + public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) { | ||
| 38 | + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken); | ||
| 39 | + return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + @Override | ||
| 43 | + public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, Long clientId) { | ||
| 44 | + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId); | ||
| 45 | + return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO); | ||
| 46 | + } | ||
| 47 | + | ||
| 33 | } | 48 | } |
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; | @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; | ||
| 11 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; |
| 12 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 13 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; |
| 14 | +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; | ||
| 14 | import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; | 15 | import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; |
| 15 | import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; | 16 | import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; |
| 16 | import cn.iocoder.yudao.module.system.service.permission.PermissionService; | 17 | import cn.iocoder.yudao.module.system.service.permission.PermissionService; |
| @@ -70,14 +71,15 @@ public class AuthController { | @@ -70,14 +71,15 @@ public class AuthController { | ||
| 70 | public CommonResult<Boolean> logout(HttpServletRequest request) { | 71 | public CommonResult<Boolean> logout(HttpServletRequest request) { |
| 71 | String token = obtainAuthorization(request, securityProperties.getTokenHeader()); | 72 | String token = obtainAuthorization(request, securityProperties.getTokenHeader()); |
| 72 | if (StrUtil.isNotBlank(token)) { | 73 | if (StrUtil.isNotBlank(token)) { |
| 73 | - authService.logout(token); | 74 | + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); |
| 74 | } | 75 | } |
| 75 | return success(true); | 76 | return success(true); |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | @PostMapping("/refresh-token") | 79 | @PostMapping("/refresh-token") |
| 79 | @ApiOperation("刷新令牌") | 80 | @ApiOperation("刷新令牌") |
| 80 | - @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 TODO 接口文档 | 81 | + @ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class) |
| 82 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 81 | public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) { | 83 | public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) { |
| 82 | return success(authService.refreshToken(refreshToken)); | 84 | return success(authService.refreshToken(refreshToken)); |
| 83 | } | 85 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2TokenController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.controller.admin.auth; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert; | ||
| 8 | +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | ||
| 9 | +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; | ||
| 10 | +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; | ||
| 11 | +import cn.iocoder.yudao.module.system.service.auth.OAuth2TokenService; | ||
| 12 | +import io.swagger.annotations.Api; | ||
| 13 | +import io.swagger.annotations.ApiImplicitParam; | ||
| 14 | +import io.swagger.annotations.ApiOperation; | ||
| 15 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 16 | +import org.springframework.web.bind.annotation.*; | ||
| 17 | + | ||
| 18 | +import javax.annotation.Resource; | ||
| 19 | +import javax.validation.Valid; | ||
| 20 | + | ||
| 21 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 22 | + | ||
| 23 | +@Api(tags = "管理后台 - OAuth2.0 令牌") | ||
| 24 | +@RestController | ||
| 25 | +@RequestMapping("/system/oauth2-token") | ||
| 26 | +public class OAuth2TokenController { | ||
| 27 | + | ||
| 28 | + @Resource | ||
| 29 | + private OAuth2TokenService oauth2TokenService; | ||
| 30 | + @Resource | ||
| 31 | + private AdminAuthService authService; | ||
| 32 | + | ||
| 33 | + @GetMapping("/page") | ||
| 34 | + @ApiOperation(value = "获得访问令牌分页", notes = "只返回有效期内的") | ||
| 35 | + @PreAuthorize("@ss.hasPermission('system:oauth2-token:page')") | ||
| 36 | + public CommonResult<PageResult<OAuth2AccessTokenRespVO>> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) { | ||
| 37 | + PageResult<OAuth2AccessTokenDO> pageResult = oauth2TokenService.getAccessTokenPage(reqVO); | ||
| 38 | + return success(OAuth2TokenConvert.INSTANCE.convert(pageResult)); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + @DeleteMapping("/delete") | ||
| 42 | + @ApiOperation("删除访问令牌") | ||
| 43 | + @ApiImplicitParam(name = "accessToken", value = "访问令牌", required = true, dataTypeClass = String.class, example = "tudou") | ||
| 44 | + @PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')") | ||
| 45 | + public CommonResult<Boolean> deleteAccessToken(@RequestParam("accessToken") String accessToken) { | ||
| 46 | + authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType()); | ||
| 47 | + return success(true); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.controller.admin.auth.vo.token; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import io.swagger.annotations.ApiModel; | ||
| 5 | +import io.swagger.annotations.ApiModelProperty; | ||
| 6 | +import lombok.Data; | ||
| 7 | +import lombok.EqualsAndHashCode; | ||
| 8 | + | ||
| 9 | +@ApiModel("管理后台 - 访问令牌分页 Request VO") | ||
| 10 | +@Data | ||
| 11 | +@EqualsAndHashCode(callSuper = true) | ||
| 12 | +public class OAuth2AccessTokenPageReqVO extends PageParam { | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "用户编号", required = true, example = "666") | ||
| 15 | + private Long userId; | ||
| 16 | + | ||
| 17 | + @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") | ||
| 18 | + private Integer userType; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "客户端编号", required = true, example = "2") | ||
| 21 | + private Long clientId; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/token/OAuth2AccessTokenRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.controller.admin.auth.vo.token; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.AllArgsConstructor; | ||
| 6 | +import lombok.Data; | ||
| 7 | +import lombok.NoArgsConstructor; | ||
| 8 | + | ||
| 9 | +import java.util.Date; | ||
| 10 | + | ||
| 11 | +@ApiModel("管理后台 - 访问令牌 Response VO") | ||
| 12 | +@Data | ||
| 13 | +@NoArgsConstructor | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +public class OAuth2AccessTokenRespVO { | ||
| 16 | + | ||
| 17 | + @ApiModelProperty(value = "编号", required = true, example = "1024") | ||
| 18 | + private Long id; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "访问令牌", required = true, example = "tudou") | ||
| 21 | + private String accessToken; | ||
| 22 | + | ||
| 23 | + @ApiModelProperty(value = "刷新令牌", required = true, example = "nice") | ||
| 24 | + private String refreshToken; | ||
| 25 | + | ||
| 26 | + @ApiModelProperty(value = "用户编号", required = true, example = "666") | ||
| 27 | + private Long userId; | ||
| 28 | + | ||
| 29 | + @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") | ||
| 30 | + private Integer userType; | ||
| 31 | + | ||
| 32 | + @ApiModelProperty(value = "客户端编号", required = true, example = "2") | ||
| 33 | + private Long clientId; | ||
| 34 | + | ||
| 35 | + @ApiModelProperty(value = "创建时间", required = true) | ||
| 36 | + private Date createTime; | ||
| 37 | + | ||
| 38 | + @ApiModelProperty(value = "过期时间", required = true) | ||
| 39 | + private Date expiresTime; | ||
| 40 | + | ||
| 41 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/OAuth2TokenConvert.java
| 1 | package cn.iocoder.yudao.module.system.convert.auth; | 1 | package cn.iocoder.yudao.module.system.convert.auth; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 3 | import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO; | 4 | import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO; |
| 5 | +import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenRespVO; | ||
| 4 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | 7 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 5 | import org.mapstruct.Mapper; | 8 | import org.mapstruct.Mapper; |
| 6 | import org.mapstruct.factory.Mappers; | 9 | import org.mapstruct.factory.Mappers; |
| @@ -12,4 +15,8 @@ public interface OAuth2TokenConvert { | @@ -12,4 +15,8 @@ public interface OAuth2TokenConvert { | ||
| 12 | 15 | ||
| 13 | OAuth2AccessTokenCheckRespDTO convert(OAuth2AccessTokenDO bean); | 16 | OAuth2AccessTokenCheckRespDTO convert(OAuth2AccessTokenDO bean); |
| 14 | 17 | ||
| 18 | + PageResult<OAuth2AccessTokenRespVO> convert(PageResult<OAuth2AccessTokenDO> page); | ||
| 19 | + | ||
| 20 | + OAuth2AccessTokenRespDTO convert2(OAuth2AccessTokenDO bean); | ||
| 21 | + | ||
| 15 | } | 22 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java
| 1 | package cn.iocoder.yudao.module.system.dal.mysql.auth; | 1 | package cn.iocoder.yudao.module.system.dal.mysql.auth; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 6 | +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; | ||
| 4 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | 7 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 5 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 9 | ||
| 10 | +import java.util.Date; | ||
| 7 | import java.util.List; | 11 | import java.util.List; |
| 8 | 12 | ||
| 9 | @Mapper | 13 | @Mapper |
| @@ -17,4 +21,13 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO | @@ -17,4 +21,13 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO | ||
| 17 | return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken); | 21 | return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken); |
| 18 | } | 22 | } |
| 19 | 23 | ||
| 24 | + default PageResult<OAuth2AccessTokenDO> selectPage(OAuth2AccessTokenPageReqVO reqVO) { | ||
| 25 | + return selectPage(reqVO, new LambdaQueryWrapperX<OAuth2AccessTokenDO>() | ||
| 26 | + .eqIfPresent(OAuth2AccessTokenDO::getUserId, reqVO.getUserId()) | ||
| 27 | + .eqIfPresent(OAuth2AccessTokenDO::getUserType, reqVO.getUserType()) | ||
| 28 | + .eqIfPresent(OAuth2AccessTokenDO::getClientId, reqVO.getClientId()) | ||
| 29 | + .gt(OAuth2AccessTokenDO::getExpiresTime, new Date()) | ||
| 30 | + .orderByDesc(OAuth2AccessTokenDO::getId)); | ||
| 31 | + } | ||
| 32 | + | ||
| 20 | } | 33 | } |
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 { | @@ -25,8 +25,9 @@ public interface AdminAuthService { | ||
| 25 | * 基于 token 退出登录 | 25 | * 基于 token 退出登录 |
| 26 | * | 26 | * |
| 27 | * @param token token | 27 | * @param token token |
| 28 | + * @param logType 登出类型 | ||
| 28 | */ | 29 | */ |
| 29 | - void logout(String token); | 30 | + void logout(String token, Integer logType); |
| 30 | 31 | ||
| 31 | /** | 32 | /** |
| 32 | * 短信验证码发送 | 33 | * 短信验证码发送 |
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; | @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; | ||
| 18 | import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; | 18 | import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; |
| 19 | import cn.iocoder.yudao.module.system.service.common.CaptchaService; | 19 | import cn.iocoder.yudao.module.system.service.common.CaptchaService; |
| 20 | import cn.iocoder.yudao.module.system.service.logger.LoginLogService; | 20 | import cn.iocoder.yudao.module.system.service.logger.LoginLogService; |
| 21 | +import cn.iocoder.yudao.module.system.service.member.MemberService; | ||
| 21 | import cn.iocoder.yudao.module.system.service.social.SocialUserService; | 22 | import cn.iocoder.yudao.module.system.service.social.SocialUserService; |
| 22 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; | 23 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 23 | import com.google.common.annotations.VisibleForTesting; | 24 | import com.google.common.annotations.VisibleForTesting; |
| @@ -51,6 +52,8 @@ public class AdminAuthServiceImpl implements AdminAuthService { | @@ -51,6 +52,8 @@ public class AdminAuthServiceImpl implements AdminAuthService { | ||
| 51 | private OAuth2TokenService oauth2TokenService; | 52 | private OAuth2TokenService oauth2TokenService; |
| 52 | @Resource | 53 | @Resource |
| 53 | private SocialUserService socialUserService; | 54 | private SocialUserService socialUserService; |
| 55 | + @Resource | ||
| 56 | + private MemberService memberService; | ||
| 54 | 57 | ||
| 55 | @Resource | 58 | @Resource |
| 56 | private Validator validator; | 59 | private Validator validator; |
| @@ -209,23 +212,27 @@ public class AdminAuthServiceImpl implements AdminAuthService { | @@ -209,23 +212,27 @@ public class AdminAuthServiceImpl implements AdminAuthService { | ||
| 209 | } | 212 | } |
| 210 | 213 | ||
| 211 | @Override | 214 | @Override |
| 212 | - public void logout(String token) { | 215 | + public void logout(String token, Integer logType) { |
| 213 | // 删除访问令牌 | 216 | // 删除访问令牌 |
| 214 | OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token); | 217 | OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token); |
| 215 | if (accessTokenDO == null) { | 218 | if (accessTokenDO == null) { |
| 216 | return; | 219 | return; |
| 217 | } | 220 | } |
| 218 | // 删除成功,则记录登出日志 | 221 | // 删除成功,则记录登出日志 |
| 219 | - createLogoutLog(accessTokenDO.getUserId()); | 222 | + createLogoutLog(accessTokenDO.getUserId(), accessTokenDO.getUserType(), logType); |
| 220 | } | 223 | } |
| 221 | 224 | ||
| 222 | - private void createLogoutLog(Long userId) { | 225 | + private void createLogoutLog(Long userId, Integer userType, Integer logType) { |
| 223 | LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); | 226 | LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); |
| 224 | - reqDTO.setLogType(LoginLogTypeEnum.LOGOUT_SELF.getType()); | 227 | + reqDTO.setLogType(logType); |
| 225 | reqDTO.setTraceId(TracerUtils.getTraceId()); | 228 | reqDTO.setTraceId(TracerUtils.getTraceId()); |
| 226 | reqDTO.setUserId(userId); | 229 | reqDTO.setUserId(userId); |
| 227 | - reqDTO.setUsername(getUsername(userId)); | ||
| 228 | - reqDTO.setUserType(getUserType().getValue()); | 230 | + reqDTO.setUserType(userType); |
| 231 | + if (ObjectUtil.notEqual(getUserType(), userType)) { | ||
| 232 | + reqDTO.setUsername(getUsername(userId)); | ||
| 233 | + } else { | ||
| 234 | + reqDTO.setUsername(memberService.getMemberUserMobile(userId)); | ||
| 235 | + } | ||
| 229 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); | 236 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); |
| 230 | reqDTO.setUserIp(ServletUtils.getClientIP()); | 237 | reqDTO.setUserIp(ServletUtils.getClientIP()); |
| 231 | reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); | 238 | reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2TokenService.java
| 1 | package cn.iocoder.yudao.module.system.service.auth; | 1 | package cn.iocoder.yudao.module.system.service.auth; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; | ||
| 3 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | 5 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 4 | 6 | ||
| 5 | /** | 7 | /** |
| @@ -64,4 +66,12 @@ public interface OAuth2TokenService { | @@ -64,4 +66,12 @@ public interface OAuth2TokenService { | ||
| 64 | */ | 66 | */ |
| 65 | OAuth2AccessTokenDO removeAccessToken(String accessToken); | 67 | OAuth2AccessTokenDO removeAccessToken(String accessToken); |
| 66 | 68 | ||
| 69 | + /** | ||
| 70 | + * 获得访问令牌分页 | ||
| 71 | + * | ||
| 72 | + * @param reqVO 请求 | ||
| 73 | + * @return 访问令牌分页 | ||
| 74 | + */ | ||
| 75 | + PageResult<OAuth2AccessTokenDO> getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO); | ||
| 76 | + | ||
| 67 | } | 77 | } |
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; | @@ -4,8 +4,10 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.util.IdUtil; | 4 | import cn.hutool.core.util.IdUtil; |
| 5 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 6 | import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | 6 | import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; | 8 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 8 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | 9 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 10 | +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.token.OAuth2AccessTokenPageReqVO; | ||
| 9 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 10 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; |
| 11 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2RefreshTokenDO; | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2RefreshTokenDO; |
| @@ -125,6 +127,11 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { | @@ -125,6 +127,11 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { | ||
| 125 | return accessTokenDO; | 127 | return accessTokenDO; |
| 126 | } | 128 | } |
| 127 | 129 | ||
| 130 | + @Override | ||
| 131 | + public PageResult<OAuth2AccessTokenDO> getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO) { | ||
| 132 | + return oauth2AccessTokenMapper.selectPage(reqVO); | ||
| 133 | + } | ||
| 134 | + | ||
| 128 | private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) { | 135 | private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) { |
| 129 | OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken()) | 136 | OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken()) |
| 130 | .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()).setClientId(clientDO.getId()) | 137 | .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()).setClientId(clientDO.getId()) |
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 { | @@ -221,7 +221,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest { | ||
| 221 | when(oauth2TokenService.removeAccessToken(eq(token))).thenReturn(accessTokenDO); | 221 | when(oauth2TokenService.removeAccessToken(eq(token))).thenReturn(accessTokenDO); |
| 222 | 222 | ||
| 223 | // 调用 | 223 | // 调用 |
| 224 | - authService.logout(token); | 224 | + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); |
| 225 | // 校验调用参数 | 225 | // 校验调用参数 |
| 226 | verify(loginLogService).createLoginLog(argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) | 226 | verify(loginLogService).createLoginLog(argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) |
| 227 | && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) | 227 | && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) |
| @@ -234,7 +234,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest { | @@ -234,7 +234,7 @@ public class AuthServiceImplTest extends BaseDbUnitTest { | ||
| 234 | String token = randomString(); | 234 | String token = randomString(); |
| 235 | 235 | ||
| 236 | // 调用 | 236 | // 调用 |
| 237 | - authService.logout(token); | 237 | + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); |
| 238 | // 校验调用参数 | 238 | // 校验调用参数 |
| 239 | verify(loginLogService, never()).createLoginLog(any()); | 239 | verify(loginLogService, never()).createLoginLog(any()); |
| 240 | } | 240 | } |
yudao-server/pom.xml
| @@ -21,11 +21,11 @@ | @@ -21,11 +21,11 @@ | ||
| 21 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> | 21 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 22 | 22 | ||
| 23 | <dependencies> | 23 | <dependencies> |
| 24 | -<!-- <dependency>--> | ||
| 25 | -<!-- <groupId>cn.iocoder.boot</groupId>--> | ||
| 26 | -<!-- <artifactId>yudao-module-member-biz</artifactId>--> | ||
| 27 | -<!-- <version>${revision}</version>--> | ||
| 28 | -<!-- </dependency>--> | 24 | + <dependency> |
| 25 | + <groupId>cn.iocoder.boot</groupId> | ||
| 26 | + <artifactId>yudao-module-member-biz</artifactId> | ||
| 27 | + <version>${revision}</version> | ||
| 28 | + </dependency> | ||
| 29 | <dependency> | 29 | <dependency> |
| 30 | <groupId>cn.iocoder.boot</groupId> | 30 | <groupId>cn.iocoder.boot</groupId> |
| 31 | <artifactId>yudao-module-system-biz</artifactId> | 31 | <artifactId>yudao-module-system-biz</artifactId> |
yudao-server/src/main/resources/application-dev.yaml
| @@ -173,8 +173,6 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta | @@ -173,8 +173,6 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta | ||
| 173 | yudao: | 173 | yudao: |
| 174 | security: | 174 | security: |
| 175 | token-header: Authorization | 175 | token-header: Authorization |
| 176 | - token-timeout: 1d | ||
| 177 | - session-timeout: 30m | ||
| 178 | mock-enable: true | 176 | mock-enable: true |
| 179 | mock-secret: test | 177 | mock-secret: test |
| 180 | xss: | 178 | xss: |
yudao-server/src/main/resources/application-local.yaml
| @@ -193,8 +193,6 @@ yudao: | @@ -193,8 +193,6 @@ yudao: | ||
| 193 | enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试 | 193 | enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试 |
| 194 | security: | 194 | security: |
| 195 | token-header: Authorization | 195 | token-header: Authorization |
| 196 | - token-timeout: 1d | ||
| 197 | - session-timeout: 1d | ||
| 198 | mock-enable: true | 196 | mock-enable: true |
| 199 | mock-secret: test | 197 | mock-secret: test |
| 200 | xss: | 198 | xss: |
yudao-ui-admin/src/api/system/session.js renamed to yudao-ui-admin/src/api/system/oauth2/oauth2Token.js
| 1 | import request from '@/utils/request' | 1 | import request from '@/utils/request' |
| 2 | 2 | ||
| 3 | -// 查询在线用户列表 | ||
| 4 | -export function list(query) { | 3 | +// 获得访问令牌分页 |
| 4 | +export function getAccessTokenPage(query) { | ||
| 5 | return request({ | 5 | return request({ |
| 6 | - url: '/system/user-session/page', | 6 | + url: '/system/oauth2-token/page', |
| 7 | method: 'get', | 7 | method: 'get', |
| 8 | params: query | 8 | params: query |
| 9 | }) | 9 | }) |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | -// 强退用户 | ||
| 13 | -export function forceLogout(tokenId) { | 12 | +// 删除访问令牌 |
| 13 | +export function deleteAccessToken(accessToken) { | ||
| 14 | return request({ | 14 | return request({ |
| 15 | - url: '/system/user-session/delete?id=' + tokenId, | 15 | + url: '/system/oauth2-token/delete?accessToken=' + accessToken, |
| 16 | method: 'delete' | 16 | method: 'delete' |
| 17 | }) | 17 | }) |
| 18 | } | 18 | } |
yudao-ui-admin/src/views/system/session/index.vue renamed to yudao-ui-admin/src/views/system/oauth2/token/index.vue
| @@ -3,11 +3,14 @@ | @@ -3,11 +3,14 @@ | ||
| 3 | <doc-alert title="用户体系" url="https://doc.iocoder.cn/user-center/" /> | 3 | <doc-alert title="用户体系" url="https://doc.iocoder.cn/user-center/" /> |
| 4 | <!-- 搜索工作栏 --> | 4 | <!-- 搜索工作栏 --> |
| 5 | <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"> | 5 | <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"> |
| 6 | - <el-form-item label="登录地址" prop="userIp"> | ||
| 7 | - <el-input v-model="queryParams.userIp" placeholder="请输入登录地址" clearable @keyup.enter.native="handleQuery"/> | 6 | + <el-form-item label="用户编号" prop="userId"> |
| 7 | + <el-input v-model="queryParams.userId" placeholder="请输入用户编号" clearable @keyup.enter.native="handleQuery"/> | ||
| 8 | </el-form-item> | 8 | </el-form-item> |
| 9 | - <el-form-item label="用户名称" prop="username"> | ||
| 10 | - <el-input v-model="queryParams.username" placeholder="请输入用户名称" clearable @keyup.enter.native="handleQuery"/> | 9 | + <el-form-item label="用户类型" prop="userType"> |
| 10 | + <el-select v-model="queryParams.userType" placeholder="请选择用户类型" clearable> | ||
| 11 | + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.USER_TYPE)" | ||
| 12 | + :key="dict.value" :label="dict.label" :value="dict.value"/> | ||
| 13 | + </el-select> | ||
| 11 | </el-form-item> | 14 | </el-form-item> |
| 12 | <el-form-item> | 15 | <el-form-item> |
| 13 | <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> | 16 | <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> |
| @@ -16,20 +19,28 @@ | @@ -16,20 +19,28 @@ | ||
| 16 | 19 | ||
| 17 | </el-form> | 20 | </el-form> |
| 18 | <el-table v-loading="loading" :data="list" style="width: 100%;"> | 21 | <el-table v-loading="loading" :data="list" style="width: 100%;"> |
| 19 | - <el-table-column label="会话编号" align="center" prop="id" width="300" /> | ||
| 20 | - <el-table-column label="登录名称" align="center" prop="username" width="100" /> | ||
| 21 | - <el-table-column label="部门名称" align="center" prop="deptName" width="100" /> | ||
| 22 | - <el-table-column label="登录地址" align="center" prop="userIp" width="100" /> | ||
| 23 | - <el-table-column label="userAgent" align="center" prop="userAgent" :show-overflow-tooltip="true" /> | ||
| 24 | - <el-table-column label="登录时间" align="center" prop="createTime" width="180"> | 22 | + <el-table-column label="访问令牌" align="center" prop="accessToken" width="300" /> |
| 23 | + <el-table-column label="刷新令牌" align="center" prop="refreshToken" width="300" /> | ||
| 24 | + <el-table-column label="用户编号" align="center" prop="userId" /> | ||
| 25 | + <el-table-column label="用户类型" align="center" prop="userType" width="100"> | ||
| 26 | + <template slot-scope="scope"> | ||
| 27 | + <dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType"/> | ||
| 28 | + </template> | ||
| 29 | + </el-table-column> | ||
| 30 | + <el-table-column label="创建时间" align="center" prop="createTime" width="180"> | ||
| 25 | <template slot-scope="scope"> | 31 | <template slot-scope="scope"> |
| 26 | <span>{{ parseTime(scope.row.createTime) }}</span> | 32 | <span>{{ parseTime(scope.row.createTime) }}</span> |
| 27 | </template> | 33 | </template> |
| 28 | </el-table-column> | 34 | </el-table-column> |
| 35 | + <el-table-column label="过期时间" align="center" prop="expiresTime" width="180"> | ||
| 36 | + <template slot-scope="scope"> | ||
| 37 | + <span>{{ parseTime(scope.row.expiresTime) }}</span> | ||
| 38 | + </template> | ||
| 39 | + </el-table-column> | ||
| 29 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | 40 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| 30 | <template slot-scope="scope"> | 41 | <template slot-scope="scope"> |
| 31 | <el-button size="mini" type="text" icon="el-icon-delete" @click="handleForceLogout(scope.row)" | 42 | <el-button size="mini" type="text" icon="el-icon-delete" @click="handleForceLogout(scope.row)" |
| 32 | - v-hasPermi="['system:user-session:delete']">强退</el-button> | 43 | + v-hasPermi="['system:oauth2-token:delete']">强退</el-button> |
| 33 | </template> | 44 | </template> |
| 34 | </el-table-column> | 45 | </el-table-column> |
| 35 | </el-table> | 46 | </el-table> |
| @@ -40,10 +51,10 @@ | @@ -40,10 +51,10 @@ | ||
| 40 | </template> | 51 | </template> |
| 41 | 52 | ||
| 42 | <script> | 53 | <script> |
| 43 | -import { list, forceLogout } from "@/api/system/session"; | 54 | +import { getAccessTokenPage, deleteAccessToken } from "@/api/system/oauth2/oauth2Token"; |
| 44 | 55 | ||
| 45 | export default { | 56 | export default { |
| 46 | - name: "Online", | 57 | + name: "OAuth2Token", |
| 47 | data() { | 58 | data() { |
| 48 | return { | 59 | return { |
| 49 | // 遮罩层 | 60 | // 遮罩层 |
| @@ -56,8 +67,8 @@ export default { | @@ -56,8 +67,8 @@ export default { | ||
| 56 | queryParams: { | 67 | queryParams: { |
| 57 | pageNo: 1, | 68 | pageNo: 1, |
| 58 | pageSize: 10, | 69 | pageSize: 10, |
| 59 | - userIp: undefined, | ||
| 60 | - username: undefined | 70 | + userId: undefined, |
| 71 | + userType: undefined | ||
| 61 | } | 72 | } |
| 62 | }; | 73 | }; |
| 63 | }, | 74 | }, |
| @@ -68,7 +79,7 @@ export default { | @@ -68,7 +79,7 @@ export default { | ||
| 68 | /** 查询登录日志列表 */ | 79 | /** 查询登录日志列表 */ |
| 69 | getList() { | 80 | getList() { |
| 70 | this.loading = true; | 81 | this.loading = true; |
| 71 | - list(this.queryParams).then(response => { | 82 | + getAccessTokenPage(this.queryParams).then(response => { |
| 72 | this.list = response.data.list; | 83 | this.list = response.data.list; |
| 73 | this.total = response.data.total; | 84 | this.total = response.data.total; |
| 74 | this.loading = false; | 85 | this.loading = false; |
| @@ -86,8 +97,8 @@ export default { | @@ -86,8 +97,8 @@ export default { | ||
| 86 | }, | 97 | }, |
| 87 | /** 强退按钮操作 */ | 98 | /** 强退按钮操作 */ |
| 88 | handleForceLogout(row) { | 99 | handleForceLogout(row) { |
| 89 | - this.$modal.confirm('是否确认强退名称为"' + row.username + '"的数据项?').then(function() { | ||
| 90 | - return forceLogout(row.id); | 100 | + this.$modal.confirm('是否确认强退令牌为"' + row.accessToken + '"的数据项?').then(function() { |
| 101 | + return deleteAccessToken(row.accessToken); | ||
| 91 | }).then(() => { | 102 | }).then(() => { |
| 92 | this.getList(); | 103 | this.getList(); |
| 93 | this.$modal.msgSuccess("强退成功"); | 104 | this.$modal.msgSuccess("强退成功"); |