Commit 024d44cea1d06ecf12f694340223d5bdd3eafb07
1 parent
71b9104a
1. 增加前台用户的 token 刷新
2. 增加前台用户的 logout 退出
Showing
13 changed files
with
166 additions
and
29 deletions
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java
| @@ -16,10 +16,7 @@ public interface SysErrorCodeConstants { | @@ -16,10 +16,7 @@ public interface SysErrorCodeConstants { | ||
| 16 | ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); | 16 | ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); |
| 17 | ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); | 17 | ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); |
| 18 | ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定"); | 18 | ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定"); |
| 19 | - | ||
| 20 | - // ========== TOKEN 模块 1002001000 ========== | ||
| 21 | - ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); | ||
| 22 | - ErrorCode TOKEN_PARSE_FAIL = new ErrorCode(1002001001, "Token 解析失败"); | 19 | + ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1002000006, "Token 已经过期"); |
| 23 | 20 | ||
| 24 | // ========== 菜单模块 1002002000 ========== | 21 | // ========== 菜单模块 1002002000 ========== |
| 25 | ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1002002000, "已经存在该名字的菜单"); | 22 | ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1002002000, "已经存在该名字的菜单"); |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
| @@ -255,15 +255,15 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -255,15 +255,15 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 255 | } | 255 | } |
| 256 | // 删除 session | 256 | // 删除 session |
| 257 | userSessionCoreService.deleteUserSession(token); | 257 | userSessionCoreService.deleteUserSession(token); |
| 258 | - // 记录登出日子和 | ||
| 259 | - this.createLogoutLog(loginUser.getUsername()); | 258 | + // 记录登出日志 |
| 259 | + this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); | ||
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | - private void createLogoutLog(String username) { | ||
| 263 | - // TODO 芋艿:这里未设置 userId | 262 | + private void createLogoutLog(Long userId, String username) { |
| 264 | SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); | 263 | SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); |
| 265 | reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); | 264 | reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); |
| 266 | reqDTO.setTraceId(TracerUtils.getTraceId()); | 265 | reqDTO.setTraceId(TracerUtils.getTraceId()); |
| 266 | + reqDTO.setUserId(userId); | ||
| 267 | reqDTO.setUserType(UserTypeEnum.ADMIN.getValue()); | 267 | reqDTO.setUserType(UserTypeEnum.ADMIN.getValue()); |
| 268 | reqDTO.setUsername(username); | 268 | reqDTO.setUsername(username); |
| 269 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); | 269 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); |
| @@ -294,7 +294,7 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -294,7 +294,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 294 | // 重新加载 SysUserDO 信息 | 294 | // 重新加载 SysUserDO 信息 |
| 295 | SysUserDO user = userService.getUser(loginUser.getId()); | 295 | SysUserDO user = userService.getUser(loginUser.getId()); |
| 296 | if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) { | 296 | if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) { |
| 297 | - throw exception(TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面 | 297 | + throw exception(AUTH_TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面 |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | // 刷新 LoginUser 缓存 | 300 | // 刷新 LoginUser 缓存 |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java
| 1 | package cn.iocoder.yudao.userserver.modules.member.service.user; | 1 | package cn.iocoder.yudao.userserver.modules.member.service.user; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.validation.Mobile; | ||
| 3 | import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; | 4 | import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; |
| 4 | 5 | ||
| 5 | /** | 6 | /** |
| @@ -18,6 +19,16 @@ public interface MbrUserService { | @@ -18,6 +19,16 @@ public interface MbrUserService { | ||
| 18 | MbrUserDO getUserByMobile(String mobile); | 19 | MbrUserDO getUserByMobile(String mobile); |
| 19 | 20 | ||
| 20 | /** | 21 | /** |
| 22 | + * 基于手机号创建用户。 | ||
| 23 | + * 如果用户已经存在,则直接进行返回 | ||
| 24 | + * | ||
| 25 | + * @param mobile 手机号 | ||
| 26 | + * @param registerIp 注册 IP | ||
| 27 | + * @return 用户对象 | ||
| 28 | + */ | ||
| 29 | + MbrUserDO createUserIfAbsent(@Mobile String mobile, String registerIp); | ||
| 30 | + | ||
| 31 | + /** | ||
| 21 | * 更新用户的最后登陆信息 | 32 | * 更新用户的最后登陆信息 |
| 22 | * | 33 | * |
| 23 | * @param id 用户编号 | 34 | * @param id 用户编号 |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
| 1 | package cn.iocoder.yudao.userserver.modules.member.service.user.impl; | 1 | package cn.iocoder.yudao.userserver.modules.member.service.user.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.IdUtil; | ||
| 4 | +import cn.hutool.core.util.RandomUtil; | ||
| 5 | +import cn.hutool.core.util.StrUtil; | ||
| 6 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; | 7 | import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; |
| 4 | import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; | 8 | import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; |
| 5 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | 9 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; |
| 6 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| 11 | +import org.springframework.security.crypto.password.PasswordEncoder; | ||
| 7 | import org.springframework.stereotype.Service; | 12 | import org.springframework.stereotype.Service; |
| 8 | 13 | ||
| 9 | import javax.annotation.Resource; | 14 | import javax.annotation.Resource; |
| @@ -23,12 +28,39 @@ public class MbrUserServiceImpl implements MbrUserService { | @@ -23,12 +28,39 @@ public class MbrUserServiceImpl implements MbrUserService { | ||
| 23 | @Resource | 28 | @Resource |
| 24 | private MbrUserMapper userMapper; | 29 | private MbrUserMapper userMapper; |
| 25 | 30 | ||
| 31 | + @Resource | ||
| 32 | + private PasswordEncoder passwordEncoder; | ||
| 33 | + | ||
| 26 | @Override | 34 | @Override |
| 27 | public MbrUserDO getUserByMobile(String mobile) { | 35 | public MbrUserDO getUserByMobile(String mobile) { |
| 28 | return userMapper.selectByMobile(mobile); | 36 | return userMapper.selectByMobile(mobile); |
| 29 | } | 37 | } |
| 30 | 38 | ||
| 31 | @Override | 39 | @Override |
| 40 | + public MbrUserDO createUserIfAbsent(String mobile, String registerIp) { | ||
| 41 | + // 用户已经存在 | ||
| 42 | + MbrUserDO user = userMapper.selectByMobile(mobile); | ||
| 43 | + if (user != null) { | ||
| 44 | + return user; | ||
| 45 | + } | ||
| 46 | + // 用户不存在,则进行创建 | ||
| 47 | + return this.createUser(mobile, registerIp); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + private MbrUserDO createUser(String mobile, String registerIp) { | ||
| 51 | + // 生成密码 | ||
| 52 | + String password = IdUtil.fastSimpleUUID(); | ||
| 53 | + // 插入用户 | ||
| 54 | + MbrUserDO user = new MbrUserDO(); | ||
| 55 | + user.setMobile(mobile); | ||
| 56 | + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 | ||
| 57 | + user.setPassword(passwordEncoder.encode(password)); // 加密密码 | ||
| 58 | + user.setRegisterIp(registerIp); | ||
| 59 | + userMapper.insert(user); | ||
| 60 | + return user; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + @Override | ||
| 32 | public void updateUserLogin(Long id, String loginIp) { | 64 | public void updateUserLogin(Long id, String loginIp) { |
| 33 | userMapper.updateById(new MbrUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date())); | 65 | userMapper.updateById(new MbrUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date())); |
| 34 | } | 66 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.http
| @@ -12,6 +12,20 @@ POST {{userServerUrl}}/send-sms-code | @@ -12,6 +12,20 @@ POST {{userServerUrl}}/send-sms-code | ||
| 12 | Content-Type: application/json | 12 | Content-Type: application/json |
| 13 | 13 | ||
| 14 | { | 14 | { |
| 15 | - "mobile": "15601691300", | 15 | + "mobile": "15601691301", |
| 16 | "scene": 1 | 16 | "scene": 1 |
| 17 | } | 17 | } |
| 18 | + | ||
| 19 | +### 请求 /sms-login 接口 => 成功 | ||
| 20 | +POST {{userServerUrl}}/sms-login | ||
| 21 | +Content-Type: application/json | ||
| 22 | + | ||
| 23 | +{ | ||
| 24 | + "mobile": "15601691301", | ||
| 25 | + "code": 9999 | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +### 请求 /logout 接口 => 成功 | ||
| 29 | +POST {{userServerUrl}}/logout | ||
| 30 | +Content-Type: application/json | ||
| 31 | +Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.java
| @@ -33,28 +33,30 @@ public class SysAuthController { | @@ -33,28 +33,30 @@ public class SysAuthController { | ||
| 33 | 33 | ||
| 34 | @PostMapping("/login") | 34 | @PostMapping("/login") |
| 35 | @ApiOperation("使用手机 + 密码登录") | 35 | @ApiOperation("使用手机 + 密码登录") |
| 36 | - public CommonResult<MbrAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { | 36 | + public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { |
| 37 | String token = authService.login(reqVO, getClientIP(), getUserAgent()); | 37 | String token = authService.login(reqVO, getClientIP(), getUserAgent()); |
| 38 | // 返回结果 | 38 | // 返回结果 |
| 39 | - return success(MbrAuthLoginRespVO.builder().token(token).build()); | 39 | + return success(SysAuthLoginRespVO.builder().token(token).build()); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | @PostMapping("/sms-login") | 42 | @PostMapping("/sms-login") |
| 43 | @ApiOperation("使用手机 + 验证码登录") | 43 | @ApiOperation("使用手机 + 验证码登录") |
| 44 | - public CommonResult<MbrAuthLoginRespVO> smsLogin(@RequestBody @Valid SysAuthLoginReqVO reqVO) { | ||
| 45 | - return null; | 44 | + public CommonResult<SysAuthLoginRespVO> smsLogin(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) { |
| 45 | + String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent()); | ||
| 46 | + // 返回结果 | ||
| 47 | + return success(SysAuthLoginRespVO.builder().token(token).build()); | ||
| 46 | } | 48 | } |
| 47 | 49 | ||
| 48 | @PostMapping("/send-sms-code") | 50 | @PostMapping("/send-sms-code") |
| 49 | @ApiOperation("发送手机验证码") | 51 | @ApiOperation("发送手机验证码") |
| 50 | - public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid MbrAuthSendSmsReqVO reqVO) { | 52 | + public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { |
| 51 | smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); | 53 | smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); |
| 52 | return success(true); | 54 | return success(true); |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | @PostMapping("/reset-password") | 57 | @PostMapping("/reset-password") |
| 56 | @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") | 58 | @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") |
| 57 | - public CommonResult<Boolean> resetPassword(@RequestBody @Valid SysAuthResetPasswordReqVO reqVO) { | 59 | + public CommonResult<Boolean> resetPassword(@RequestBody @Valid MbrAuthResetPasswordReqVO reqVO) { |
| 58 | return null; | 60 | return null; |
| 59 | } | 61 | } |
| 60 | 62 | ||
| @@ -74,7 +76,7 @@ public class SysAuthController { | @@ -74,7 +76,7 @@ public class SysAuthController { | ||
| 74 | 76 | ||
| 75 | @PostMapping("/social-login") | 77 | @PostMapping("/social-login") |
| 76 | @ApiOperation("社交登录,使用 code 授权码") | 78 | @ApiOperation("社交登录,使用 code 授权码") |
| 77 | - public CommonResult<MbrAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) { | 79 | + public CommonResult<SysAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) { |
| 78 | // String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent()); | 80 | // String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent()); |
| 79 | // // 返回结果 | 81 | // // 返回结果 |
| 80 | // return success(MbrAuthLoginRespVO.builder().token(token).build()); | 82 | // return success(MbrAuthLoginRespVO.builder().token(token).build()); |
| @@ -83,7 +85,7 @@ public class SysAuthController { | @@ -83,7 +85,7 @@ public class SysAuthController { | ||
| 83 | 85 | ||
| 84 | @PostMapping("/social-login2") | 86 | @PostMapping("/social-login2") |
| 85 | @ApiOperation("社交登录,使用 code 授权码 + 账号密码") | 87 | @ApiOperation("社交登录,使用 code 授权码 + 账号密码") |
| 86 | - public CommonResult<MbrAuthLoginRespVO> socialLogin2(@RequestBody @Valid MbrAuthSocialLogin2ReqVO reqVO) { | 88 | + public CommonResult<SysAuthLoginRespVO> socialLogin2(@RequestBody @Valid MbrAuthSocialLogin2ReqVO reqVO) { |
| 87 | // String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); | 89 | // String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); |
| 88 | // // 返回结果 | 90 | // // 返回结果 |
| 89 | // return success(MbrAuthLoginRespVO.builder().token(token).build()); | 91 | // return success(MbrAuthLoginRespVO.builder().token(token).build()); |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthResetPasswordReqVO.java renamed to yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthResetPasswordReqVO.java
| @@ -16,7 +16,7 @@ import javax.validation.constraints.Pattern; | @@ -16,7 +16,7 @@ import javax.validation.constraints.Pattern; | ||
| 16 | @NoArgsConstructor | 16 | @NoArgsConstructor |
| 17 | @AllArgsConstructor | 17 | @AllArgsConstructor |
| 18 | @Builder | 18 | @Builder |
| 19 | -public class SysAuthResetPasswordReqVO { | 19 | +public class MbrAuthResetPasswordReqVO { |
| 20 | 20 | ||
| 21 | @ApiModelProperty(value = "新密码", required = true, example = "buzhidao") | 21 | @ApiModelProperty(value = "新密码", required = true, example = "buzhidao") |
| 22 | @NotEmpty(message = "新密码不能为空") | 22 | @NotEmpty(message = "新密码不能为空") |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthLoginRespVO.java renamed to yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthLoginRespVO.java
| @@ -12,7 +12,7 @@ import lombok.NoArgsConstructor; | @@ -12,7 +12,7 @@ import lombok.NoArgsConstructor; | ||
| 12 | @NoArgsConstructor | 12 | @NoArgsConstructor |
| 13 | @AllArgsConstructor | 13 | @AllArgsConstructor |
| 14 | @Builder | 14 | @Builder |
| 15 | -public class MbrAuthLoginRespVO { | 15 | +public class SysAuthLoginRespVO { |
| 16 | 16 | ||
| 17 | @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma") | 17 | @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma") |
| 18 | private String token; | 18 | private String token; |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSendSmsReqVO.java renamed to yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthSendSmsReqVO.java
| @@ -13,7 +13,7 @@ import javax.validation.constraints.NotNull; | @@ -13,7 +13,7 @@ import javax.validation.constraints.NotNull; | ||
| 13 | @ApiModel("发送手机验证码 Response VO") | 13 | @ApiModel("发送手机验证码 Response VO") |
| 14 | @Data | 14 | @Data |
| 15 | @Accessors(chain = true) | 15 | @Accessors(chain = true) |
| 16 | -public class MbrAuthSendSmsReqVO { | 16 | +public class SysAuthSendSmsReqVO { |
| 17 | 17 | ||
| 18 | @ApiModelProperty(value = "手机号", example = "15601691234") | 18 | @ApiModelProperty(value = "手机号", example = "15601691234") |
| 19 | @Mobile | 19 | @Mobile |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSmsLoginReqVO.java renamed to yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthSmsLoginReqVO.java
| @@ -17,18 +17,13 @@ import javax.validation.constraints.Pattern; | @@ -17,18 +17,13 @@ import javax.validation.constraints.Pattern; | ||
| 17 | @NoArgsConstructor | 17 | @NoArgsConstructor |
| 18 | @AllArgsConstructor | 18 | @AllArgsConstructor |
| 19 | @Builder | 19 | @Builder |
| 20 | -public class MbrAuthSmsLoginReqVO { | 20 | +public class SysAuthSmsLoginReqVO { |
| 21 | 21 | ||
| 22 | @ApiModelProperty(value = "手机号", required = true, example = "15601691300") | 22 | @ApiModelProperty(value = "手机号", required = true, example = "15601691300") |
| 23 | @NotEmpty(message = "手机号不能为空") | 23 | @NotEmpty(message = "手机号不能为空") |
| 24 | @Mobile | 24 | @Mobile |
| 25 | private String mobile; | 25 | private String mobile; |
| 26 | 26 | ||
| 27 | - @ApiModelProperty(value = "密码", required = true, example = "buzhidao") | ||
| 28 | - @NotEmpty(message = "密码不能为空") | ||
| 29 | - @Length(min = 4, max = 16, message = "密码长度为 4-16 位") | ||
| 30 | - private String password; | ||
| 31 | - | ||
| 32 | @ApiModelProperty(value = "手机验证码", required = true, example = "1024") | 27 | @ApiModelProperty(value = "手机验证码", required = true, example = "1024") |
| 33 | @NotEmpty(message = "手机验证码不能为空") | 28 | @NotEmpty(message = "手机验证码不能为空") |
| 34 | @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") | 29 | @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/SysErrorCodeConstants.java
| @@ -13,6 +13,7 @@ public interface SysErrorCodeConstants { | @@ -13,6 +13,7 @@ public interface SysErrorCodeConstants { | ||
| 13 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1005000000, "登录失败,账号密码不正确"); | 13 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1005000000, "登录失败,账号密码不正确"); |
| 14 | ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1005000001, "登录失败,账号被禁用"); | 14 | ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1005000001, "登录失败,账号被禁用"); |
| 15 | ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1005000002, "登录失败"); // 登录失败的兜底,未知原因 | 15 | ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1005000002, "登录失败"); // 登录失败的兜底,未知原因 |
| 16 | + ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1005000003, "Token 已经过期"); | ||
| 16 | 17 | ||
| 17 | // ========== SMS CODE 模块 1005001000 ========== | 18 | // ========== SMS CODE 模块 1005001000 ========== |
| 18 | ErrorCode USER_SMS_CODE_NOT_FOUND = new ErrorCode(1005001000, "验证码不存在"); | 19 | ErrorCode USER_SMS_CODE_NOT_FOUND = new ErrorCode(1005001000, "验证码不存在"); |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysAuthService.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.system.service.auth; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.system.service.auth; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; | 3 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; |
| 4 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO; | 4 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO; |
| 5 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSmsLoginReqVO; | ||
| 5 | 6 | ||
| 6 | import javax.validation.Valid; | 7 | import javax.validation.Valid; |
| 7 | 8 | ||
| @@ -24,4 +25,14 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | @@ -24,4 +25,14 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | ||
| 24 | */ | 25 | */ |
| 25 | String login(@Valid SysAuthLoginReqVO reqVO, String userIp, String userAgent); | 26 | String login(@Valid SysAuthLoginReqVO reqVO, String userIp, String userAgent); |
| 26 | 27 | ||
| 28 | + /** | ||
| 29 | + * 手机 + 验证码登陆 | ||
| 30 | + * | ||
| 31 | + * @param reqVO 登陆信息 | ||
| 32 | + * @param userIp 用户 IP | ||
| 33 | + * @param userAgent 用户 UA | ||
| 34 | + * @return 身份令牌,使用 JWT 方式 | ||
| 35 | + */ | ||
| 36 | + String smsLogin(@Valid SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent); | ||
| 37 | + | ||
| 27 | } | 38 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
| 1 | package cn.iocoder.yudao.userserver.modules.system.service.auth.impl; | 1 | package cn.iocoder.yudao.userserver.modules.system.service.auth.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 3 | import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; | 4 | import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; |
| 4 | import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; | 5 | import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; |
| 5 | import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO; | 6 | import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO; |
| 7 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 8 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | 9 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; |
| 7 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 10 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 8 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 11 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 9 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO; | 12 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO; |
| 13 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSmsLoginReqVO; | ||
| 10 | import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert; | 14 | import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert; |
| 11 | import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; | 15 | import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; |
| 16 | +import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | ||
| 12 | import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | 17 | import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; |
| 13 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | 18 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; |
| 14 | import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum; | 19 | import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum; |
| 15 | import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum; | 20 | import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum; |
| 21 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||
| 16 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
| 17 | import org.springframework.context.annotation.Lazy; | 23 | import org.springframework.context.annotation.Lazy; |
| 18 | import org.springframework.security.authentication.AuthenticationManager; | 24 | import org.springframework.security.authentication.AuthenticationManager; |
| @@ -24,7 +30,7 @@ import org.springframework.security.core.AuthenticationException; | @@ -24,7 +30,7 @@ import org.springframework.security.core.AuthenticationException; | ||
| 24 | import org.springframework.security.core.userdetails.UserDetails; | 30 | import org.springframework.security.core.userdetails.UserDetails; |
| 25 | import org.springframework.security.core.userdetails.UsernameNotFoundException; | 31 | import org.springframework.security.core.userdetails.UsernameNotFoundException; |
| 26 | import org.springframework.stereotype.Service; | 32 | import org.springframework.stereotype.Service; |
| 27 | -import org.springframework.util.Assert; | 33 | +import org.springframework.transaction.annotation.Transactional; |
| 28 | 34 | ||
| 29 | import javax.annotation.Resource; | 35 | import javax.annotation.Resource; |
| 30 | import java.util.Objects; | 36 | import java.util.Objects; |
| @@ -48,6 +54,8 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -48,6 +54,8 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 48 | @Resource | 54 | @Resource |
| 49 | private MbrUserService userService; | 55 | private MbrUserService userService; |
| 50 | @Resource | 56 | @Resource |
| 57 | + private SysSmsCodeService smsCodeService; | ||
| 58 | + @Resource | ||
| 51 | private SysLoginLogCoreService loginLogCoreService; | 59 | private SysLoginLogCoreService loginLogCoreService; |
| 52 | @Resource | 60 | @Resource |
| 53 | private SysUserSessionCoreService userSessionCoreService; | 61 | private SysUserSessionCoreService userSessionCoreService; |
| @@ -72,6 +80,25 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -72,6 +80,25 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 72 | return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); | 80 | return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); |
| 73 | } | 81 | } |
| 74 | 82 | ||
| 83 | + @Override | ||
| 84 | + @Transactional | ||
| 85 | + public String smsLogin(SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { | ||
| 86 | + // 校验验证码 | ||
| 87 | + smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.LOGIN_BY_SMS.getScene(), | ||
| 88 | + reqVO.getCode(), userIp); | ||
| 89 | + | ||
| 90 | + // 获得获得注册用户 | ||
| 91 | + MbrUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); | ||
| 92 | + Assert.notNull(user, "获取用户失败,结果为空"); | ||
| 93 | + | ||
| 94 | + // 执行登陆 | ||
| 95 | + this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SMS, SysLoginResultEnum.SUCCESS); | ||
| 96 | + LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||
| 97 | + | ||
| 98 | + // 缓存登录用户到 Redis 中,返回 sessionId 编号 | ||
| 99 | + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); | ||
| 100 | + } | ||
| 101 | + | ||
| 75 | private LoginUser login0(String username, String password) { | 102 | private LoginUser login0(String username, String password) { |
| 76 | final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME; | 103 | final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME; |
| 77 | // 用户验证 | 104 | // 用户验证 |
| @@ -120,7 +147,31 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -120,7 +147,31 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 120 | 147 | ||
| 121 | @Override | 148 | @Override |
| 122 | public LoginUser verifyTokenAndRefresh(String token) { | 149 | public LoginUser verifyTokenAndRefresh(String token) { |
| 123 | - return null; | 150 | + // 获得 LoginUser |
| 151 | + LoginUser loginUser = userSessionCoreService.getLoginUser(token); | ||
| 152 | + if (loginUser == null) { | ||
| 153 | + return null; | ||
| 154 | + } | ||
| 155 | + // 刷新 LoginUser 缓存 | ||
| 156 | + this.refreshLoginUserCache(token, loginUser); | ||
| 157 | + return loginUser; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + private void refreshLoginUserCache(String token, LoginUser loginUser) { | ||
| 161 | + // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 | ||
| 162 | + if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < | ||
| 163 | + userSessionCoreService.getSessionTimeoutMillis() / 3) { | ||
| 164 | + return; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + // 重新加载 MbrUserDO 信息 | ||
| 168 | + MbrUserDO user = userService.getUser(loginUser.getId()); | ||
| 169 | + if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) { | ||
| 170 | + throw exception(AUTH_TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面 | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + // 刷新 LoginUser 缓存 | ||
| 174 | + userSessionCoreService.refreshUserSession(token, loginUser); | ||
| 124 | } | 175 | } |
| 125 | 176 | ||
| 126 | @Override | 177 | @Override |
| @@ -130,6 +181,8 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -130,6 +181,8 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 130 | if (user == null) { | 181 | if (user == null) { |
| 131 | throw new UsernameNotFoundException(String.valueOf(userId)); | 182 | throw new UsernameNotFoundException(String.valueOf(userId)); |
| 132 | } | 183 | } |
| 184 | + | ||
| 185 | + // 执行登陆 | ||
| 133 | this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); | 186 | this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); |
| 134 | 187 | ||
| 135 | // 创建 LoginUser 对象 | 188 | // 创建 LoginUser 对象 |
| @@ -138,7 +191,28 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -138,7 +191,28 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 138 | 191 | ||
| 139 | @Override | 192 | @Override |
| 140 | public void logout(String token) { | 193 | public void logout(String token) { |
| 194 | + // 查询用户信息 | ||
| 195 | + LoginUser loginUser = userSessionCoreService.getLoginUser(token); | ||
| 196 | + if (loginUser == null) { | ||
| 197 | + return; | ||
| 198 | + } | ||
| 199 | + // 删除 session | ||
| 200 | + userSessionCoreService.deleteUserSession(token); | ||
| 201 | + // 记录登出日志 | ||
| 202 | + this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); | ||
| 203 | + } | ||
| 141 | 204 | ||
| 205 | + private void createLogoutLog(Long userId, String username) { | ||
| 206 | + SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); | ||
| 207 | + reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); | ||
| 208 | + reqDTO.setTraceId(TracerUtils.getTraceId()); | ||
| 209 | + reqDTO.setUserId(userId); | ||
| 210 | + reqDTO.setUserType(UserTypeEnum.MEMBER.getValue()); | ||
| 211 | + reqDTO.setUsername(username); | ||
| 212 | + reqDTO.setUserAgent(ServletUtils.getUserAgent()); | ||
| 213 | + reqDTO.setUserIp(ServletUtils.getClientIP()); | ||
| 214 | + reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult()); | ||
| 215 | + loginLogCoreService.createLoginLog(reqDTO); | ||
| 142 | } | 216 | } |
| 143 | 217 | ||
| 144 | } | 218 | } |