Commit 024d44cea1d06ecf12f694340223d5bdd3eafb07

Authored by YunaiV
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 }