refactor: 会话失效、数据权限和实时推送重构
This commit is contained in:
@@ -18,9 +18,22 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
/**
|
||||
* 短信验证码认证 Provider
|
||||
* <p>
|
||||
* 实现 Spring Security 的 {@link AuthenticationProvider} 接口,处理短信验证码登录认证。
|
||||
* <p>
|
||||
* 认证流程:
|
||||
* <ol>
|
||||
* <li>根据手机号查询用户信息</li>
|
||||
* <li>校验用户状态(是否禁用)</li>
|
||||
* <li>校验短信验证码(与 Redis 缓存比对)</li>
|
||||
* <li>验证成功后删除验证码,防止重复使用</li>
|
||||
* <li>返回已认证的 Authentication</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Ray.Hao
|
||||
* @since 2.17.0
|
||||
* @see SmsAuthenticationToken
|
||||
* @see AuthenticationProvider
|
||||
*/
|
||||
@Slf4j
|
||||
public class SmsAuthenticationProvider implements AuthenticationProvider {
|
||||
@@ -29,58 +42,79 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
|
||||
public SmsAuthenticationProvider(UserService userService, RedisTemplate<String, Object> redisTemplate) {
|
||||
this.userService = userService;
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信验证码认证逻辑,参考 Spring Security 认证密码校验流程
|
||||
* 执行短信验证码认证
|
||||
*
|
||||
* @param authentication 认证对象
|
||||
* @return 认证后的 Authentication 对象
|
||||
* @throws AuthenticationException 认证异常
|
||||
* @see org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider#authenticate(Authentication)
|
||||
* @param authentication 未认证的 {@link SmsAuthenticationToken}
|
||||
* @return 已认证的 {@link SmsAuthenticationToken}
|
||||
* @throws AuthenticationException 认证失败异常
|
||||
*/
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
String mobile = (String) authentication.getPrincipal();
|
||||
String inputVerifyCode = (String) authentication.getCredentials();
|
||||
|
||||
// 参数校验
|
||||
if (StrUtil.isBlank(mobile)) {
|
||||
log.warn("短信验证码登录失败:手机号为空");
|
||||
throw new CaptchaValidationException("手机号不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(inputVerifyCode)) {
|
||||
log.warn("短信验证码登录失败:验证码为空,手机号={}", mobile);
|
||||
throw new CaptchaValidationException("验证码不能为空");
|
||||
}
|
||||
|
||||
// 根据手机号获取用户信息
|
||||
UserAuthInfo userAuthInfo = userService.getAuthInfoByMobile(mobile);
|
||||
|
||||
if (userAuthInfo == null) {
|
||||
log.warn("短信验证码登录失败:用户不存在,手机号={}", mobile);
|
||||
throw new UsernameNotFoundException("用户不存在");
|
||||
}
|
||||
|
||||
// 检查用户状态是否有效
|
||||
if (ObjectUtil.notEqual(userAuthInfo.getStatus(), 1)) {
|
||||
log.warn("短信验证码登录失败:用户已禁用,用户名={}", userAuthInfo.getUsername());
|
||||
throw new DisabledException("用户已被禁用");
|
||||
}
|
||||
|
||||
// 校验发送短信验证码的手机号是否与当前登录用户一致
|
||||
// 校验短信验证码
|
||||
String cacheKey = StrUtil.format(RedisConstants.Captcha.SMS_LOGIN_CODE, mobile);
|
||||
String cachedVerifyCode = (String) redisTemplate.opsForValue().get(cacheKey);
|
||||
|
||||
if (!StrUtil.equals(inputVerifyCode, cachedVerifyCode)) {
|
||||
throw new CaptchaValidationException("验证码错误");
|
||||
} else {
|
||||
// 验证成功后删除验证码
|
||||
redisTemplate.delete(cacheKey);
|
||||
if (cachedVerifyCode == null) {
|
||||
log.warn("短信验证码登录失败:验证码已过期,手机号={}", mobile);
|
||||
throw new CaptchaValidationException("验证码已过期,请重新获取");
|
||||
}
|
||||
|
||||
if (!StrUtil.equals(inputVerifyCode, cachedVerifyCode)) {
|
||||
log.warn("短信验证码登录失败:验证码错误,手机号={}", mobile);
|
||||
throw new CaptchaValidationException("验证码错误");
|
||||
}
|
||||
|
||||
// 验证成功后删除验证码,防止重复使用
|
||||
redisTemplate.delete(cacheKey);
|
||||
|
||||
// 构建认证后的用户详情信息
|
||||
SysUserDetails userDetails = new SysUserDetails(userAuthInfo);
|
||||
|
||||
log.info("短信验证码登录成功:用户名={},手机号={}", userAuthInfo.getUsername(), mobile);
|
||||
|
||||
// 创建已认证的 SmsAuthenticationToken
|
||||
return SmsAuthenticationToken.authenticated(
|
||||
userDetails,
|
||||
userDetails.getAuthorities()
|
||||
);
|
||||
return SmsAuthenticationToken.authenticated(userDetails, userDetails.getAuthorities());
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持的认证类型
|
||||
*
|
||||
* @param authentication 认证类型
|
||||
* @return 是否支持该认证类型
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return SmsAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
|
||||
Reference in New Issue
Block a user