去除 Spring Security 的 Member 的 loadUsername,使用自己定义的 login0 实现

This commit is contained in:
YunaiV
2022-05-08 02:33:34 +08:00
parent 3bd7e8e682
commit 5e8648508e
17 changed files with 63 additions and 383 deletions

View File

@@ -1,5 +1,5 @@
### 请求 /login 接口 => 成功
POST {{appApi}}/member/login
POST {{appApi}}/member/auth/login
Content-Type: application/json
tenant-id: {{appTenentId}}

View File

@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.member.convert.auth;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.authentication.SpringSecurityUser;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
@@ -11,7 +10,6 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
@@ -21,11 +19,6 @@ public interface AuthConvert {
LoginUser convert(MemberUserDO bean);
@Mapping(source = "mobile", target = "username")
SpringSecurityUser convert2(MemberUserDO user);
LoginUser convert(SpringSecurityUser bean);
SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialBindLoginReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialQuickLoginReqVO reqVO);
SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppSocialUserUnbindReqVO reqVO);

View File

@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.member.service.auth;
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
import javax.validation.Valid;
@@ -12,7 +11,7 @@ import javax.validation.Valid;
*
* @author 芋道源码
*/
public interface MemberAuthService extends SecurityAuthFrameworkService {
public interface MemberAuthService {
/**
* 手机 + 密码登录

View File

@@ -1,11 +1,12 @@
package cn.iocoder.yudao.module.member.service.auth;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
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.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
@@ -21,14 +22,6 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -49,10 +42,6 @@ import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
@Slf4j
public class MemberAuthServiceImpl implements MemberAuthService {
@Resource
@Lazy // 延迟加载,因为存在相互依赖的问题
private AuthenticationManager authenticationManager;
@Resource
private MemberUserService userService;
@Resource
@@ -69,17 +58,6 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Resource
private MemberUserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
// 获取 username 对应的 SysUserDO
MemberUserDO user = userService.getUserByMobile(mobile);
if (user == null) {
throw new UsernameNotFoundException(mobile);
}
// 创建 LoginUser 对象
return AuthConvert.INSTANCE.convert2(user);
}
@Override
public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) {
// 使用手机 + 密码,进行登录。
@@ -157,43 +135,34 @@ public class MemberAuthServiceImpl implements MemberAuthService {
return socialUserApi.getAuthorizeUrl(type, redirectUri);
}
private LoginUser login0(String username, String password) {
final LoginLogTypeEnum logType = LoginLogTypeEnum.LOGIN_USERNAME;
// 用户验证
Authentication authentication;
try {
// 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证
// 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息
authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken(
username, password, getUserType()));
} catch (BadCredentialsException badCredentialsException) {
this.createLoginLog(null, username, logType, LoginResultEnum.BAD_CREDENTIALS);
private LoginUser login0(String mobile, String password) {
final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_MOBILE;
// 校验账号是否存在
MemberUserDO user = userService.getUserByMobile(mobile);
if (user == null) {
createLoginLog(null, mobile, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
} catch (DisabledException disabledException) {
this.createLoginLog(null, username, logType, LoginResultEnum.USER_DISABLED);
throw exception(AUTH_LOGIN_USER_DISABLED);
} catch (AuthenticationException authenticationException) {
log.error("[login0][username({}) 发生未知异常]", username, authenticationException);
this.createLoginLog(null, username, logType, LoginResultEnum.UNKNOWN_ERROR);
throw exception(AUTH_LOGIN_FAIL_UNKNOWN);
}
Assert.notNull(authentication.getPrincipal(), "Principal 不会为空");
return (LoginUser) authentication.getPrincipal();
if (!userService.isPasswordMatch(password, user.getPassword())) {
createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
}
// 校验是否禁用
if (ObjectUtil.notEqual(user.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED);
throw exception(AUTH_LOGIN_USER_DISABLED);
}
// 构建 User 对象
return buildLoginUser(user);
}
private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) {
// 获得用户
if (userId == null) {
MemberUserDO user = userService.getUserByMobile(mobile);
userId = user != null ? user.getId() : null;
}
// 插入登录日志
LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
reqDTO.setLogType(logType.getType());
reqDTO.setTraceId(TracerUtils.getTraceId());
if (userId != null) {
reqDTO.setUserId(userId);
}
reqDTO.setUserId(userId);
reqDTO.setUserType(getUserType().getValue());
reqDTO.setUsername(mobile);
reqDTO.setUserAgent(ServletUtils.getUserAgent());
@@ -206,11 +175,6 @@ public class MemberAuthServiceImpl implements MemberAuthService {
}
}
@Override
public LoginUser verifyTokenAndRefresh(String token) {
return userSessionApi.getLoginUser(token);
}
@Override
public void logout(String token) {
// 查询用户信息
@@ -224,17 +188,13 @@ public class MemberAuthServiceImpl implements MemberAuthService {
createLogoutLog(loginUser.getId());
}
@Override
public UserTypeEnum getUserType() {
return UserTypeEnum.MEMBER;
}
@Override
public void updatePassword(Long userId, AppAuthUpdatePasswordReqVO reqVO) {
// 检验旧密码
MemberUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
// 更新用户密码
// TODO 芋艿:需要重构到用户模块
userMapper.updateById(MemberUserDO.builder().id(userDO.getId())
.password(passwordEncoder.encode(reqVO.getPassword())).build());
}
@@ -312,4 +272,8 @@ public class MemberAuthServiceImpl implements MemberAuthService {
return user != null ? user.getMobile() : null;
}
private UserTypeEnum getUserType() {
return UserTypeEnum.MEMBER;
}
}

View File

@@ -69,4 +69,13 @@ public interface MemberUserService {
*/
void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO);
/**
* 判断密码是否匹配
*
* @param rawPassword 未加密的密码
* @param encodedPassword 加密后的密码
* @return 是否匹配
*/
boolean isPasswordMatch(String rawPassword, String encodedPassword);
}

View File

@@ -69,7 +69,7 @@ public class MemberUserServiceImpl implements MemberUserService {
MemberUserDO user = new MemberUserDO();
user.setMobile(mobile);
user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
user.setPassword(passwordEncoder.encode(password)); // 加密密码
user.setPassword(encodePassword(password)); // 加密密码
user.setRegisterIp(registerIp);
memberUserMapper.insert(user);
return user;
@@ -127,6 +127,21 @@ public class MemberUserServiceImpl implements MemberUserService {
memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build());
}
@Override
public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
return passwordEncoder.matches(rawPassword, encodedPassword);
}
/**
* 对密码进行加密
*
* @param password 密码
* @return 加密后的密码
*/
private String encodePassword(String password) {
return passwordEncoder.encode(password);
}
@VisibleForTesting
public MemberUserDO checkUserExists(Long id) {
if (id == null) {

View File

@@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
@@ -38,8 +37,8 @@ import static org.mockito.Mockito.when;
@Import({MemberAuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest {
@MockBean
private AuthenticationManager authenticationManager;
// TODO @芋艿:登录相关的单测,待补全
@MockBean
private MemberUserService userService;
@MockBean