mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	1. 增加前台用户的 token 刷新
2. 增加前台用户的 logout 退出
This commit is contained in:
		| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.userserver.modules.member.service.user; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.Mobile; | ||||
| import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; | ||||
|  | ||||
| /** | ||||
| @@ -17,6 +18,16 @@ public interface MbrUserService { | ||||
|      */ | ||||
|     MbrUserDO getUserByMobile(String mobile); | ||||
|  | ||||
|     /** | ||||
|      * 基于手机号创建用户。 | ||||
|      * 如果用户已经存在,则直接进行返回 | ||||
|      * | ||||
|      * @param mobile 手机号 | ||||
|      * @param registerIp 注册 IP | ||||
|      * @return 用户对象 | ||||
|      */ | ||||
|     MbrUserDO createUserIfAbsent(@Mobile String mobile, String registerIp); | ||||
|  | ||||
|     /** | ||||
|      * 更新用户的最后登陆信息 | ||||
|      * | ||||
|   | ||||
| @@ -1,9 +1,14 @@ | ||||
| package cn.iocoder.yudao.userserver.modules.member.service.user.impl; | ||||
|  | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| import cn.hutool.core.util.RandomUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; | ||||
| import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; | ||||
| import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| @@ -23,11 +28,38 @@ public class MbrUserServiceImpl implements MbrUserService { | ||||
|     @Resource | ||||
|     private MbrUserMapper userMapper; | ||||
|  | ||||
|     @Resource | ||||
|     private PasswordEncoder passwordEncoder; | ||||
|  | ||||
|     @Override | ||||
|     public MbrUserDO getUserByMobile(String mobile) { | ||||
|         return userMapper.selectByMobile(mobile); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public MbrUserDO createUserIfAbsent(String mobile, String registerIp) { | ||||
|         // 用户已经存在 | ||||
|         MbrUserDO user = userMapper.selectByMobile(mobile); | ||||
|         if (user != null) { | ||||
|             return user; | ||||
|         } | ||||
|         // 用户不存在,则进行创建 | ||||
|         return this.createUser(mobile, registerIp); | ||||
|     } | ||||
|  | ||||
|     private MbrUserDO createUser(String mobile, String registerIp) { | ||||
|         // 生成密码 | ||||
|         String password = IdUtil.fastSimpleUUID(); | ||||
|         // 插入用户 | ||||
|         MbrUserDO user = new MbrUserDO(); | ||||
|         user.setMobile(mobile); | ||||
|         user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 | ||||
|         user.setPassword(passwordEncoder.encode(password)); // 加密密码 | ||||
|         user.setRegisterIp(registerIp); | ||||
|         userMapper.insert(user); | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void updateUserLogin(Long id, String loginIp) { | ||||
|         userMapper.updateById(new MbrUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date())); | ||||
|   | ||||
| @@ -12,6 +12,20 @@ POST {{userServerUrl}}/send-sms-code | ||||
| Content-Type: application/json | ||||
|  | ||||
| { | ||||
|   "mobile": "15601691300", | ||||
|   "mobile": "15601691301", | ||||
|   "scene": 1 | ||||
| } | ||||
|  | ||||
| ### 请求 /sms-login 接口 => 成功 | ||||
| POST {{userServerUrl}}/sms-login | ||||
| Content-Type: application/json | ||||
|  | ||||
| { | ||||
|   "mobile": "15601691301", | ||||
|   "code": 9999 | ||||
| } | ||||
|  | ||||
| ### 请求 /logout 接口 => 成功 | ||||
| POST {{userServerUrl}}/logout | ||||
| Content-Type: application/json | ||||
| Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 | ||||
|   | ||||
| @@ -33,28 +33,30 @@ public class SysAuthController { | ||||
|  | ||||
|     @PostMapping("/login") | ||||
|     @ApiOperation("使用手机 + 密码登录") | ||||
|     public CommonResult<MbrAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { | ||||
|     public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { | ||||
|         String token = authService.login(reqVO, getClientIP(), getUserAgent()); | ||||
|         // 返回结果 | ||||
|         return success(MbrAuthLoginRespVO.builder().token(token).build()); | ||||
|         return success(SysAuthLoginRespVO.builder().token(token).build()); | ||||
|     } | ||||
|  | ||||
|     @PostMapping("/sms-login") | ||||
|     @ApiOperation("使用手机 + 验证码登录") | ||||
|     public CommonResult<MbrAuthLoginRespVO> smsLogin(@RequestBody @Valid SysAuthLoginReqVO reqVO) { | ||||
|         return null; | ||||
|     public CommonResult<SysAuthLoginRespVO> smsLogin(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) { | ||||
|         String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent()); | ||||
|         // 返回结果 | ||||
|         return success(SysAuthLoginRespVO.builder().token(token).build()); | ||||
|     } | ||||
|  | ||||
|     @PostMapping("/send-sms-code") | ||||
|     @ApiOperation("发送手机验证码") | ||||
|     public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid MbrAuthSendSmsReqVO reqVO) { | ||||
|     public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { | ||||
|         smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); | ||||
|         return success(true); | ||||
|     } | ||||
|  | ||||
|     @PostMapping("/reset-password") | ||||
|     @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") | ||||
|     public CommonResult<Boolean> resetPassword(@RequestBody @Valid SysAuthResetPasswordReqVO reqVO) { | ||||
|     public CommonResult<Boolean> resetPassword(@RequestBody @Valid MbrAuthResetPasswordReqVO reqVO) { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| @@ -74,7 +76,7 @@ public class SysAuthController { | ||||
|  | ||||
|     @PostMapping("/social-login") | ||||
|     @ApiOperation("社交登录,使用 code 授权码") | ||||
|         public CommonResult<MbrAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) { | ||||
|         public CommonResult<SysAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) { | ||||
| //        String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent()); | ||||
| //        // 返回结果 | ||||
| //        return success(MbrAuthLoginRespVO.builder().token(token).build()); | ||||
| @@ -83,7 +85,7 @@ public class SysAuthController { | ||||
|  | ||||
|     @PostMapping("/social-login2") | ||||
|     @ApiOperation("社交登录,使用 code 授权码 + 账号密码") | ||||
|     public CommonResult<MbrAuthLoginRespVO> socialLogin2(@RequestBody @Valid MbrAuthSocialLogin2ReqVO reqVO) { | ||||
|     public CommonResult<SysAuthLoginRespVO> socialLogin2(@RequestBody @Valid MbrAuthSocialLogin2ReqVO reqVO) { | ||||
| //        String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); | ||||
| //        // 返回结果 | ||||
| //        return success(MbrAuthLoginRespVO.builder().token(token).build()); | ||||
|   | ||||
| @@ -16,7 +16,7 @@ import javax.validation.constraints.Pattern; | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| @Builder | ||||
| public class SysAuthResetPasswordReqVO { | ||||
| public class MbrAuthResetPasswordReqVO { | ||||
| 
 | ||||
|     @ApiModelProperty(value = "新密码", required = true, example = "buzhidao") | ||||
|     @NotEmpty(message = "新密码不能为空") | ||||
| @@ -12,7 +12,7 @@ import lombok.NoArgsConstructor; | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| @Builder | ||||
| public class MbrAuthLoginRespVO { | ||||
| public class SysAuthLoginRespVO { | ||||
| 
 | ||||
|     @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma") | ||||
|     private String token; | ||||
| @@ -13,7 +13,7 @@ import javax.validation.constraints.NotNull; | ||||
| @ApiModel("发送手机验证码 Response VO") | ||||
| @Data | ||||
| @Accessors(chain = true) | ||||
| public class MbrAuthSendSmsReqVO { | ||||
| public class SysAuthSendSmsReqVO { | ||||
| 
 | ||||
|     @ApiModelProperty(value = "手机号", example = "15601691234") | ||||
|     @Mobile | ||||
| @@ -17,18 +17,13 @@ import javax.validation.constraints.Pattern; | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| @Builder | ||||
| public class MbrAuthSmsLoginReqVO { | ||||
| public class SysAuthSmsLoginReqVO { | ||||
| 
 | ||||
|     @ApiModelProperty(value = "手机号", required = true, example = "15601691300") | ||||
|     @NotEmpty(message = "手机号不能为空") | ||||
|     @Mobile | ||||
|     private String mobile; | ||||
| 
 | ||||
|     @ApiModelProperty(value = "密码", required = true, example = "buzhidao") | ||||
|     @NotEmpty(message = "密码不能为空") | ||||
|     @Length(min = 4, max = 16, message = "密码长度为 4-16 位") | ||||
|     private String password; | ||||
| 
 | ||||
|     @ApiModelProperty(value = "手机验证码", required = true, example = "1024") | ||||
|     @NotEmpty(message = "手机验证码不能为空") | ||||
|     @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") | ||||
| @@ -13,6 +13,7 @@ public interface SysErrorCodeConstants { | ||||
|     ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1005000000, "登录失败,账号密码不正确"); | ||||
|     ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1005000001, "登录失败,账号被禁用"); | ||||
|     ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1005000002, "登录失败"); // 登录失败的兜底,未知原因 | ||||
|     ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1005000003, "Token 已经过期"); | ||||
|  | ||||
|     // ========== SMS CODE 模块 1005001000 ========== | ||||
|     ErrorCode USER_SMS_CODE_NOT_FOUND = new ErrorCode(1005001000, "验证码不存在"); | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.system.service.auth; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; | ||||
| import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO; | ||||
| import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSmsLoginReqVO; | ||||
|  | ||||
| import javax.validation.Valid; | ||||
|  | ||||
| @@ -24,4 +25,14 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | ||||
|      */ | ||||
|     String login(@Valid SysAuthLoginReqVO reqVO, String userIp, String userAgent); | ||||
|  | ||||
|     /** | ||||
|      * 手机 + 验证码登陆 | ||||
|      * | ||||
|      * @param reqVO 登陆信息 | ||||
|      * @param userIp 用户 IP | ||||
|      * @param userAgent 用户 UA | ||||
|      * @return 身份令牌,使用 JWT 方式 | ||||
|      */ | ||||
|     String smsLogin(@Valid SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,24 @@ | ||||
| package cn.iocoder.yudao.userserver.modules.system.service.auth.impl; | ||||
|  | ||||
| import cn.hutool.core.lang.Assert; | ||||
| import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; | ||||
| import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; | ||||
| import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO; | ||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||||
| import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | ||||
| import cn.iocoder.yudao.framework.security.core.LoginUser; | ||||
| import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO; | ||||
| import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSmsLoginReqVO; | ||||
| import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert; | ||||
| import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO; | ||||
| import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | ||||
| import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | ||||
| import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | ||||
| import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum; | ||||
| import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum; | ||||
| import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.security.authentication.AuthenticationManager; | ||||
| @@ -24,7 +30,7 @@ import org.springframework.security.core.AuthenticationException; | ||||
| import org.springframework.security.core.userdetails.UserDetails; | ||||
| import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.util.Assert; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| import java.util.Objects; | ||||
| @@ -48,6 +54,8 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|     @Resource | ||||
|     private MbrUserService userService; | ||||
|     @Resource | ||||
|     private SysSmsCodeService smsCodeService; | ||||
|     @Resource | ||||
|     private SysLoginLogCoreService loginLogCoreService; | ||||
|     @Resource | ||||
|     private SysUserSessionCoreService userSessionCoreService; | ||||
| @@ -72,6 +80,25 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|         return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public String smsLogin(SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { | ||||
|         // 校验验证码 | ||||
|         smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.LOGIN_BY_SMS.getScene(), | ||||
|                 reqVO.getCode(), userIp); | ||||
|  | ||||
|         // 获得获得注册用户 | ||||
|         MbrUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); | ||||
|         Assert.notNull(user, "获取用户失败,结果为空"); | ||||
|  | ||||
|         // 执行登陆 | ||||
|         this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SMS, SysLoginResultEnum.SUCCESS); | ||||
|         LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||||
|  | ||||
|         // 缓存登录用户到 Redis 中,返回 sessionId 编号 | ||||
|         return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); | ||||
|     } | ||||
|  | ||||
|     private LoginUser login0(String username, String password) { | ||||
|         final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME; | ||||
|         // 用户验证 | ||||
| @@ -120,7 +147,31 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|  | ||||
|     @Override | ||||
|     public LoginUser verifyTokenAndRefresh(String token) { | ||||
|         return null; | ||||
|         // 获得 LoginUser | ||||
|         LoginUser loginUser = userSessionCoreService.getLoginUser(token); | ||||
|         if (loginUser == null) { | ||||
|             return null; | ||||
|         } | ||||
|         // 刷新 LoginUser 缓存 | ||||
|         this.refreshLoginUserCache(token, loginUser); | ||||
|         return loginUser; | ||||
|     } | ||||
|  | ||||
|     private void refreshLoginUserCache(String token, LoginUser loginUser) { | ||||
|         // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 | ||||
|         if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < | ||||
|                 userSessionCoreService.getSessionTimeoutMillis() / 3) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 重新加载 MbrUserDO 信息 | ||||
|         MbrUserDO user = userService.getUser(loginUser.getId()); | ||||
|         if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) { | ||||
|             throw exception(AUTH_TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面 | ||||
|         } | ||||
|  | ||||
|         // 刷新 LoginUser 缓存 | ||||
|         userSessionCoreService.refreshUserSession(token, loginUser); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -130,6 +181,8 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|         if (user == null) { | ||||
|             throw new UsernameNotFoundException(String.valueOf(userId)); | ||||
|         } | ||||
|  | ||||
|         // 执行登陆 | ||||
|         this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); | ||||
|  | ||||
|         // 创建 LoginUser 对象 | ||||
| @@ -138,7 +191,28 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|  | ||||
|     @Override | ||||
|     public void logout(String token) { | ||||
|         // 查询用户信息 | ||||
|         LoginUser loginUser = userSessionCoreService.getLoginUser(token); | ||||
|         if (loginUser == null) { | ||||
|             return; | ||||
|         } | ||||
|         // 删除 session | ||||
|         userSessionCoreService.deleteUserSession(token); | ||||
|         // 记录登出日志 | ||||
|         this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); | ||||
|     } | ||||
|  | ||||
|     private void createLogoutLog(Long userId, String username) { | ||||
|         SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); | ||||
|         reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); | ||||
|         reqDTO.setTraceId(TracerUtils.getTraceId()); | ||||
|         reqDTO.setUserId(userId); | ||||
|         reqDTO.setUserType(UserTypeEnum.MEMBER.getValue()); | ||||
|         reqDTO.setUsername(username); | ||||
|         reqDTO.setUserAgent(ServletUtils.getUserAgent()); | ||||
|         reqDTO.setUserIp(ServletUtils.getClientIP()); | ||||
|         reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult()); | ||||
|         loginLogCoreService.createLoginLog(reqDTO); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV