Commit 3bd7e8e6829300d9f1d059b5b50123df3fc67af4

Authored by YunaiV
1 parent 3351ebbb

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

yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java
@@ -105,16 +105,6 @@ public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsA @@ -105,16 +105,6 @@ public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsA
105 return selectService(request).verifyTokenAndRefresh(token); 105 return selectService(request).verifyTokenAndRefresh(token);
106 } 106 }
107 107
108 - /**  
109 - * 基于 token 退出登录  
110 - *  
111 - * @param request 请求  
112 - * @param token token  
113 - */  
114 - public void logout(HttpServletRequest request, String token) {  
115 - selectService(request).logout(token);  
116 - }  
117 -  
118 private SecurityAuthFrameworkService selectService(HttpServletRequest request) { 108 private SecurityAuthFrameworkService selectService(HttpServletRequest request) {
119 // 第一步,获得用户类型 109 // 第一步,获得用户类型
120 UserTypeEnum userType = getUserType(request); 110 UserTypeEnum userType = getUserType(request);
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthFrameworkService.java
@@ -21,13 +21,6 @@ public interface SecurityAuthFrameworkService extends UserDetailsService { @@ -21,13 +21,6 @@ public interface SecurityAuthFrameworkService extends UserDetailsService {
21 LoginUser verifyTokenAndRefresh(String token); 21 LoginUser verifyTokenAndRefresh(String token);
22 22
23 /** 23 /**
24 - * 基于 token 退出登录  
25 - *  
26 - * @param token token  
27 - */  
28 - void logout(String token);  
29 -  
30 - /**  
31 * 获得用户类型。每个用户类型,对应一个 SecurityAuthFrameworkService 实现类。 24 * 获得用户类型。每个用户类型,对应一个 SecurityAuthFrameworkService 实现类。
32 * 25 *
33 * @return 用户类型 26 * @return 用户类型
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java
@@ -25,6 +25,13 @@ public interface MemberAuthService extends SecurityAuthFrameworkService { @@ -25,6 +25,13 @@ public interface MemberAuthService extends SecurityAuthFrameworkService {
25 String login(@Valid AppAuthLoginReqVO reqVO, String userIp, String userAgent); 25 String login(@Valid AppAuthLoginReqVO reqVO, String userIp, String userAgent);
26 26
27 /** 27 /**
  28 + * 基于 token 退出登录
  29 + *
  30 + * @param token token
  31 + */
  32 + void logout(String token);
  33 +
  34 + /**
28 * 手机 + 验证码登陆 35 * 手机 + 验证码登陆
29 * 36 *
30 * @param reqVO 登陆信息 37 * @param reqVO 登陆信息
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
@@ -12,7 +12,6 @@ public interface ErrorCodeConstants { @@ -12,7 +12,6 @@ public interface ErrorCodeConstants {
12 // ========== AUTH 模块 1002000000 ========== 12 // ========== AUTH 模块 1002000000 ==========
13 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确"); 13 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确");
14 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用"); 14 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用");
15 - ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登录失败的兜底,未知原因  
16 ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); 15 ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在");
17 ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); 16 ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确");
18 ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定"); 17 ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定");
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java
@@ -26,8 +26,6 @@ public interface AuthConvert { @@ -26,8 +26,6 @@ public interface AuthConvert {
26 26
27 SpringSecurityUser convert2(AdminUserDO user); 27 SpringSecurityUser convert2(AdminUserDO user);
28 28
29 - LoginUser convert(SpringSecurityUser bean);  
30 -  
31 default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { 29 default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
32 return AuthPermissionInfoRespVO.builder() 30 return AuthPermissionInfoRespVO.builder()
33 .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build()) 31 .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java
1 package cn.iocoder.yudao.module.system.service.auth; 1 package cn.iocoder.yudao.module.system.service.auth;
2 2
3 -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;  
4 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; 3 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
  4 +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
5 5
6 import javax.validation.Valid; 6 import javax.validation.Valid;
7 7
8 /** 8 /**
9 * 管理后台的认证 Service 接口 9 * 管理后台的认证 Service 接口
10 * 10 *
11 - * 提供用户的账号密码登录、token 的校验等认证相关的功能 11 + * 提供用户的登录、登出的能力
12 * 12 *
13 * @author 芋道源码 13 * @author 芋道源码
14 */ 14 */
@@ -25,6 +25,13 @@ public interface AdminAuthService extends SecurityAuthFrameworkService { @@ -25,6 +25,13 @@ public interface AdminAuthService extends SecurityAuthFrameworkService {
25 String login(@Valid AuthLoginReqVO reqVO, String userIp, String userAgent); 25 String login(@Valid AuthLoginReqVO reqVO, String userIp, String userAgent);
26 26
27 /** 27 /**
  28 + * 基于 token 退出登录
  29 + *
  30 + * @param token token
  31 + */
  32 + void logout(String token);
  33 +
  34 + /**
28 * 短信验证码发送 35 * 短信验证码发送
29 * 36 *
30 * @param reqVO 发送请求 37 * @param reqVO 发送请求
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.auth; 1 package cn.iocoder.yudao.module.system.service.auth;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 5 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; 6 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
5 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 7 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
6 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; 8 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
7 import cn.iocoder.yudao.framework.security.core.LoginUser; 9 import cn.iocoder.yudao.framework.security.core.LoginUser;
8 -import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken;  
9 -import cn.iocoder.yudao.framework.security.core.authentication.SpringSecurityUser;  
10 import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; 10 import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
11 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; 11 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
12 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*; 12 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
@@ -19,18 +19,11 @@ import cn.iocoder.yudao.module.system.service.common.CaptchaService; @@ -19,18 +19,11 @@ import cn.iocoder.yudao.module.system.service.common.CaptchaService;
19 import cn.iocoder.yudao.module.system.service.logger.LoginLogService; 19 import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
20 import cn.iocoder.yudao.module.system.service.social.SocialUserService; 20 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
21 import cn.iocoder.yudao.module.system.service.user.AdminUserService; 21 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
  22 +import com.google.common.annotations.VisibleForTesting;
22 import lombok.extern.slf4j.Slf4j; 23 import lombok.extern.slf4j.Slf4j;
23 -import org.springframework.beans.factory.annotation.Autowired;  
24 -import org.springframework.context.annotation.Lazy;  
25 -import org.springframework.security.authentication.AuthenticationManager;  
26 -import org.springframework.security.authentication.BadCredentialsException;  
27 -import org.springframework.security.authentication.DisabledException;  
28 -import org.springframework.security.core.Authentication;  
29 -import org.springframework.security.core.AuthenticationException;  
30 import org.springframework.security.core.userdetails.UserDetails; 24 import org.springframework.security.core.userdetails.UserDetails;
31 import org.springframework.security.core.userdetails.UsernameNotFoundException; 25 import org.springframework.security.core.userdetails.UsernameNotFoundException;
32 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
33 -import org.springframework.util.Assert;  
34 27
35 import javax.annotation.Resource; 28 import javax.annotation.Resource;
36 import javax.validation.Validator; 29 import javax.validation.Validator;
@@ -50,11 +43,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -50,11 +43,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
50 public class AdminAuthServiceImpl implements AdminAuthService { 43 public class AdminAuthServiceImpl implements AdminAuthService {
51 44
52 @Resource 45 @Resource
53 - @Lazy // 延迟加载,因为存在相互依赖的问题  
54 - private AuthenticationManager authenticationManager;  
55 -  
56 - @Autowired  
57 - @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // UserService 存在重名  
58 private AdminUserService userService; 46 private AdminUserService userService;
59 @Resource 47 @Resource
60 private CaptchaService captchaService; 48 private CaptchaService captchaService;
@@ -72,17 +60,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { @@ -72,17 +60,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
72 private SmsCodeApi smsCodeApi; 60 private SmsCodeApi smsCodeApi;
73 61
74 @Override 62 @Override
75 - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {  
76 - // 获取 username 对应的 AdminUserDO  
77 - AdminUserDO user = userService.getUserByUsername(username);  
78 - if (user == null) {  
79 - throw new UsernameNotFoundException(username);  
80 - }  
81 - // 创建 LoginUser 对象  
82 - return AuthConvert.INSTANCE.convert2(user);  
83 - }  
84 -  
85 - @Override  
86 public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) { 63 public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) {
87 // 判断验证码是否正确 64 // 判断验证码是否正确
88 verifyCaptcha(reqVO); 65 verifyCaptcha(reqVO);
@@ -124,7 +101,8 @@ public class AdminAuthServiceImpl implements AdminAuthService { @@ -124,7 +101,8 @@ public class AdminAuthServiceImpl implements AdminAuthService {
124 LoginLogTypeEnum.LOGIN_MOBILE, userIp, userAgent); 101 LoginLogTypeEnum.LOGIN_MOBILE, userIp, userAgent);
125 } 102 }
126 103
127 - private void verifyCaptcha(AuthLoginReqVO reqVO) { 104 + @VisibleForTesting
  105 + void verifyCaptcha(AuthLoginReqVO reqVO) {
128 // 如果验证码关闭,则不进行校验 106 // 如果验证码关闭,则不进行校验
129 if (!captchaService.isCaptchaEnable()) { 107 if (!captchaService.isCaptchaEnable()) {
130 return; 108 return;
@@ -149,46 +127,36 @@ public class AdminAuthServiceImpl implements AdminAuthService { @@ -149,46 +127,36 @@ public class AdminAuthServiceImpl implements AdminAuthService {
149 captchaService.deleteCaptchaCode(reqVO.getUuid()); 127 captchaService.deleteCaptchaCode(reqVO.getUuid());
150 } 128 }
151 129
152 - private LoginUser login0(String username, String password) { 130 + @VisibleForTesting
  131 + LoginUser login0(String username, String password) {
153 final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME; 132 final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
154 - // 用户验证  
155 - Authentication authentication;  
156 - try {  
157 - // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证  
158 - // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息  
159 - authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken(  
160 - username, password, getUserType()));  
161 - } catch (BadCredentialsException badCredentialsException) { 133 + // 校验账号是否存在
  134 + AdminUserDO user = userService.getUserByUsername(username);
  135 + if (user == null) {
162 createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); 136 createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
163 throw exception(AUTH_LOGIN_BAD_CREDENTIALS); 137 throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
164 - } catch (DisabledException disabledException) {  
165 - createLoginLog(null, username, logTypeEnum, LoginResultEnum.USER_DISABLED); 138 + }
  139 + if (!userService.isPasswordMatch(password, user.getPassword())) {
  140 + createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
  141 + throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
  142 + }
  143 + // 校验是否禁用
  144 + if (ObjectUtil.notEqual(user.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
  145 + createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED);
166 throw exception(AUTH_LOGIN_USER_DISABLED); 146 throw exception(AUTH_LOGIN_USER_DISABLED);
167 - } catch (AuthenticationException authenticationException) {  
168 - log.error("[login0][username({}) 发生未知异常]", username, authenticationException);  
169 - createLoginLog(null, username, logTypeEnum, LoginResultEnum.UNKNOWN_ERROR);  
170 - throw exception(AUTH_LOGIN_FAIL_UNKNOWN);  
171 } 147 }
172 - Assert.notNull(authentication.getPrincipal(), "Principal 不会为空"); 148 +
173 // 构建 User 对象 149 // 构建 User 对象
174 - return AuthConvert.INSTANCE.convert((SpringSecurityUser) authentication.getPrincipal())  
175 - .setUserType(getUserType().getValue()); 150 + return buildLoginUser(user);
176 } 151 }
177 152
178 private void createLoginLog(Long userId, String username, 153 private void createLoginLog(Long userId, String username,
179 LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) { 154 LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
180 - // 获得用户  
181 - if (userId == null) {  
182 - AdminUserDO user = userService.getUserByUsername(username);  
183 - userId = user != null ? user.getId() : null;  
184 - }  
185 // 插入登录日志 155 // 插入登录日志
186 LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); 156 LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
187 reqDTO.setLogType(logTypeEnum.getType()); 157 reqDTO.setLogType(logTypeEnum.getType());
188 reqDTO.setTraceId(TracerUtils.getTraceId()); 158 reqDTO.setTraceId(TracerUtils.getTraceId());
189 - if (userId != null) {  
190 - reqDTO.setUserId(userId);  
191 - } 159 + reqDTO.setUserId(userId);
192 reqDTO.setUserType(getUserType().getValue()); 160 reqDTO.setUserType(getUserType().getValue());
193 reqDTO.setUsername(username); 161 reqDTO.setUsername(username);
194 reqDTO.setUserAgent(ServletUtils.getUserAgent()); 162 reqDTO.setUserAgent(ServletUtils.getUserAgent());
@@ -293,4 +261,8 @@ public class AdminAuthServiceImpl implements AdminAuthService { @@ -293,4 +261,8 @@ public class AdminAuthServiceImpl implements AdminAuthService {
293 return user != null ? user.getUsername() : null; 261 return user != null ? user.getUsername() : null;
294 } 262 }
295 263
  264 + @Override
  265 + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  266 + return null;
  267 + }
296 } 268 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
@@ -105,7 +105,6 @@ public interface AdminUserService { @@ -105,7 +105,6 @@ public interface AdminUserService {
105 */ 105 */
106 AdminUserDO getUserByMobile(String mobile); 106 AdminUserDO getUserByMobile(String mobile);
107 107
108 -  
109 /** 108 /**
110 * 获得用户分页列表 109 * 获得用户分页列表
111 * 110 *
@@ -209,4 +208,13 @@ public interface AdminUserService { @@ -209,4 +208,13 @@ public interface AdminUserService {
209 */ 208 */
210 List<AdminUserDO> getUsersByStatus(Integer status); 209 List<AdminUserDO> getUsersByStatus(Integer status);
211 210
  211 + /**
  212 + * 判断密码是否匹配
  213 + *
  214 + * @param rawPassword 未加密的密码
  215 + * @param encodedPassword 加密后的密码
  216 + * @return 是否匹配
  217 + */
  218 + boolean isPasswordMatch(String rawPassword, String encodedPassword);
  219 +
212 } 220 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
@@ -148,7 +148,7 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -148,7 +148,7 @@ public class AdminUserServiceImpl implements AdminUserService {
148 checkOldPassword(id, reqVO.getOldPassword()); 148 checkOldPassword(id, reqVO.getOldPassword());
149 // 执行更新 149 // 执行更新
150 AdminUserDO updateObj = new AdminUserDO().setId(id); 150 AdminUserDO updateObj = new AdminUserDO().setId(id);
151 - updateObj.setPassword(passwordEncoder.encode(reqVO.getNewPassword())); // 加密密码 151 + updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
152 userMapper.updateById(updateObj); 152 userMapper.updateById(updateObj);
153 } 153 }
154 154
@@ -172,7 +172,7 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -172,7 +172,7 @@ public class AdminUserServiceImpl implements AdminUserService {
172 // 更新密码 172 // 更新密码
173 AdminUserDO updateObj = new AdminUserDO(); 173 AdminUserDO updateObj = new AdminUserDO();
174 updateObj.setId(id); 174 updateObj.setId(id);
175 - updateObj.setPassword(passwordEncoder.encode(password)); // 加密密码 175 + updateObj.setPassword(encodePassword(password)); // 加密密码
176 userMapper.updateById(updateObj); 176 userMapper.updateById(updateObj);
177 } 177 }
178 178
@@ -205,11 +205,6 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -205,11 +205,6 @@ public class AdminUserServiceImpl implements AdminUserService {
205 return userMapper.selectByUsername(username); 205 return userMapper.selectByUsername(username);
206 } 206 }
207 207
208 - /**  
209 - * 通过手机号获取用户  
210 - * @param mobile  
211 - * @return  
212 - */  
213 @Override 208 @Override
214 public AdminUserDO getUserByMobile(String mobile) { 209 public AdminUserDO getUserByMobile(String mobile) {
215 return userMapper.selectByMobile(mobile); 210 return userMapper.selectByMobile(mobile);
@@ -395,7 +390,7 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -395,7 +390,7 @@ public class AdminUserServiceImpl implements AdminUserService {
395 if (user == null) { 390 if (user == null) {
396 throw exception(USER_NOT_EXISTS); 391 throw exception(USER_NOT_EXISTS);
397 } 392 }
398 - if (!passwordEncoder.matches(oldPassword, user.getPassword())) { 393 + if (!isPasswordMatch(oldPassword, user.getPassword())) {
399 throw exception(USER_PASSWORD_FAILED); 394 throw exception(USER_PASSWORD_FAILED);
400 } 395 }
401 } 396 }
@@ -421,7 +416,7 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -421,7 +416,7 @@ public class AdminUserServiceImpl implements AdminUserService {
421 AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername()); 416 AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
422 if (existUser == null) { 417 if (existUser == null) {
423 userMapper.insert(UserConvert.INSTANCE.convert(importUser) 418 userMapper.insert(UserConvert.INSTANCE.convert(importUser)
424 - .setPassword(passwordEncoder.encode(userInitPassword))); // 设置默认密码 419 + .setPassword(encodePassword(userInitPassword))); // 设置默认密码
425 respVO.getCreateUsernames().add(importUser.getUsername()); 420 respVO.getCreateUsernames().add(importUser.getUsername());
426 return; 421 return;
427 } 422 }
@@ -443,4 +438,19 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -443,4 +438,19 @@ public class AdminUserServiceImpl implements AdminUserService {
443 return userMapper.selectListByStatus(status); 438 return userMapper.selectListByStatus(status);
444 } 439 }
445 440
  441 + @Override
  442 + public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
  443 + return passwordEncoder.matches(rawPassword, encodedPassword);
  444 + }
  445 +
  446 + /**
  447 + * 对密码进行加密
  448 + *
  449 + * @param password 密码
  450 + * @return 加密后的密码
  451 + */
  452 + private String encodePassword(String password) {
  453 + return passwordEncoder.encode(password);
  454 + }
  455 +
446 } 456 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java
1 package cn.iocoder.yudao.module.system.service.auth; 1 package cn.iocoder.yudao.module.system.service.auth;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.security.core.LoginUser; 4 import cn.iocoder.yudao.framework.security.core.LoginUser;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 import cn.iocoder.yudao.framework.test.core.util.AssertUtils; 6 import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
@@ -9,7 +10,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; @@ -9,7 +10,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
9 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; 10 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
10 import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; 11 import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
11 import cn.iocoder.yudao.module.system.service.common.CaptchaService; 12 import cn.iocoder.yudao.module.system.service.common.CaptchaService;
12 -import cn.iocoder.yudao.module.system.service.dept.PostService;  
13 import cn.iocoder.yudao.module.system.service.logger.LoginLogService; 13 import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
14 import cn.iocoder.yudao.module.system.service.social.SocialUserService; 14 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
15 import cn.iocoder.yudao.module.system.service.user.AdminUserService; 15 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
@@ -17,23 +17,16 @@ import org.junit.jupiter.api.BeforeEach; @@ -17,23 +17,16 @@ import org.junit.jupiter.api.BeforeEach;
17 import org.junit.jupiter.api.Test; 17 import org.junit.jupiter.api.Test;
18 import org.springframework.boot.test.mock.mockito.MockBean; 18 import org.springframework.boot.test.mock.mockito.MockBean;
19 import org.springframework.context.annotation.Import; 19 import org.springframework.context.annotation.Import;
20 -import org.springframework.security.authentication.AuthenticationManager;  
21 -import org.springframework.security.authentication.BadCredentialsException;  
22 -import org.springframework.security.authentication.DisabledException;  
23 -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;  
24 -import org.springframework.security.core.Authentication;  
25 -import org.springframework.security.core.AuthenticationException;  
26 -import org.springframework.security.core.userdetails.UsernameNotFoundException;  
27 20
28 import javax.annotation.Resource; 21 import javax.annotation.Resource;
29 import javax.validation.Validator; 22 import javax.validation.Validator;
30 -import java.util.Set;  
31 23
  24 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
32 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 25 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
33 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; 26 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  27 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
34 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 28 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
35 import static org.junit.jupiter.api.Assertions.assertEquals; 29 import static org.junit.jupiter.api.Assertions.assertEquals;
36 -import static org.junit.jupiter.api.Assertions.assertThrows;  
37 import static org.mockito.ArgumentMatchers.eq; 30 import static org.mockito.ArgumentMatchers.eq;
38 import static org.mockito.Mockito.*; 31 import static org.mockito.Mockito.*;
39 32
@@ -46,10 +39,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest { @@ -46,10 +39,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
46 @MockBean 39 @MockBean
47 private AdminUserService userService; 40 private AdminUserService userService;
48 @MockBean 41 @MockBean
49 - private AuthenticationManager authenticationManager;  
50 - @MockBean  
51 - private Authentication authentication;  
52 - @MockBean  
53 private CaptchaService captchaService; 42 private CaptchaService captchaService;
54 @MockBean 43 @MockBean
55 private LoginLogService loginLogService; 44 private LoginLogService loginLogService;
@@ -58,8 +47,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest { @@ -58,8 +47,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
58 @MockBean 47 @MockBean
59 private SocialUserService socialService; 48 private SocialUserService socialService;
60 @MockBean 49 @MockBean
61 - private PostService postService;  
62 - @MockBean  
63 private SmsCodeApi smsCodeApi; 50 private SmsCodeApi smsCodeApi;
64 51
65 @MockBean 52 @MockBean
@@ -71,131 +58,124 @@ public class AuthServiceImplTest extends BaseDbUnitTest { @@ -71,131 +58,124 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
71 } 58 }
72 59
73 @Test 60 @Test
74 - public void testLoadUserByUsername_success() { 61 + public void testLogin0_success() {
75 // 准备参数 62 // 准备参数
76 String username = randomString(); 63 String username = randomString();
77 - // mock 方法  
78 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username)); 64 + String password = randomString();
  65 + // mock user 数据
  66 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username)
  67 + .setPassword(password).setStatus(CommonStatusEnum.ENABLE.getStatus()));
79 when(userService.getUserByUsername(eq(username))).thenReturn(user); 68 when(userService.getUserByUsername(eq(username))).thenReturn(user);
  69 + // mock password 匹配
  70 + when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true);
80 71
81 // 调用 72 // 调用
82 - LoginUser loginUser = (LoginUser) authService.loadUserByUsername(username); 73 + LoginUser loginUser = authService.login0(username, password);
83 // 校验 74 // 校验
84 - AssertUtils.assertPojoEquals(user, loginUser, "updateTime"); 75 + assertPojoEquals(user, loginUser);
85 } 76 }
86 77
87 @Test 78 @Test
88 - public void testLoadUserByUsername_userNotFound() { 79 + public void testLogin0_userNotFound() {
89 // 准备参数 80 // 准备参数
90 String username = randomString(); 81 String username = randomString();
91 - // mock 方法 82 + String password = randomString();
92 83
93 // 调用, 并断言异常 84 // 调用, 并断言异常
94 - assertThrows(UsernameNotFoundException.class, // 抛出 UsernameNotFoundException 异常  
95 - () -> authService.loadUserByUsername(username),  
96 - username); // 异常提示为 username 85 + AssertUtils.assertServiceException(() -> authService.login0(username, password),
  86 + AUTH_LOGIN_BAD_CREDENTIALS);
  87 + verify(loginLogService).createLoginLog(
  88 + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
  89 + && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult())
  90 + && o.getUserId() == null)
  91 + );
97 } 92 }
98 93
99 @Test 94 @Test
100 - public void testLogin_captchaNotFound() { 95 + public void testLogin0_badCredentials() {
101 // 准备参数 96 // 准备参数
102 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class);  
103 - String userIp = randomString();  
104 - String userAgent = randomString(); 97 + String username = randomString();
  98 + String password = randomString();
  99 + // mock user 数据
  100 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username)
  101 + .setPassword(password).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  102 + when(userService.getUserByUsername(eq(username))).thenReturn(user);
105 103
106 // 调用, 并断言异常 104 // 调用, 并断言异常
107 - assertServiceException(() -> authService.login(reqVO, userIp, userAgent), AUTH_LOGIN_CAPTCHA_NOT_FOUND);  
108 - // 校验调用参数  
109 - verify(loginLogService, times(1)).createLoginLog(  
110 - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())  
111 - && o.getResult().equals(LoginResultEnum.CAPTCHA_NOT_FOUND.getResult())) 105 + AssertUtils.assertServiceException(() -> authService.login0(username, password),
  106 + AUTH_LOGIN_BAD_CREDENTIALS);
  107 + verify(loginLogService).createLoginLog(
  108 + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
  109 + && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult())
  110 + && o.getUserId().equals(user.getId()))
112 ); 111 );
113 } 112 }
114 113
115 @Test 114 @Test
116 - public void testLogin_captchaCodeError() { 115 + public void testLogin0_userDisabled() {
117 // 准备参数 116 // 准备参数
118 - String userIp = randomString();  
119 - String userAgent = randomString();  
120 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class);  
121 -  
122 - // mock 验证码不正确  
123 - String code = randomString();  
124 - when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(code); 117 + String username = randomString();
  118 + String password = randomString();
  119 + // mock user 数据
  120 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username)
  121 + .setPassword(password).setStatus(CommonStatusEnum.DISABLE.getStatus()));
  122 + when(userService.getUserByUsername(eq(username))).thenReturn(user);
  123 + // mock password 匹配
  124 + when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true);
125 125
126 // 调用, 并断言异常 126 // 调用, 并断言异常
127 - assertServiceException(() -> authService.login(reqVO, userIp, userAgent), AUTH_LOGIN_CAPTCHA_CODE_ERROR);  
128 - // 校验调用参数  
129 - verify(loginLogService, times(1)).createLoginLog(  
130 - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())  
131 - && o.getResult().equals(LoginResultEnum.CAPTCHA_CODE_ERROR.getResult())) 127 + AssertUtils.assertServiceException(() -> authService.login0(username, password),
  128 + AUTH_LOGIN_USER_DISABLED);
  129 + verify(loginLogService).createLoginLog(
  130 + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
  131 + && o.getResult().equals(LoginResultEnum.USER_DISABLED.getResult())
  132 + && o.getUserId().equals(user.getId()))
132 ); 133 );
133 } 134 }
134 135
135 @Test 136 @Test
136 - public void testLogin_badCredentials() { 137 + public void testCaptcha_success() {
137 // 准备参数 138 // 准备参数
138 - String userIp = randomString();  
139 - String userAgent = randomString();  
140 AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); 139 AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class);
  140 +
141 // mock 验证码正确 141 // mock 验证码正确
142 when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(reqVO.getCode()); 142 when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(reqVO.getCode());
143 - // mock 抛出异常  
144 - when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword())))  
145 - .thenThrow(new BadCredentialsException("测试账号或密码不正确"));  
146 143
147 - // 调用, 并断言异常  
148 - assertServiceException(() -> authService.login(reqVO, userIp, userAgent), AUTH_LOGIN_BAD_CREDENTIALS);  
149 - // 校验调用参数  
150 - verify(captchaService, times(1)).deleteCaptchaCode(reqVO.getUuid());  
151 - verify(loginLogService, times(1)).createLoginLog(  
152 - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())  
153 - && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult()))  
154 - ); 144 + // 调用
  145 + authService.verifyCaptcha(reqVO);
  146 + // 断言
  147 + verify(captchaService).deleteCaptchaCode(reqVO.getUuid());
155 } 148 }
156 149
157 @Test 150 @Test
158 - public void testLogin_userDisabled() { 151 + public void testCaptcha_notFound() {
159 // 准备参数 152 // 准备参数
160 - String userIp = randomString();  
161 - String userAgent = randomString();  
162 AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); 153 AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class);
163 154
164 - // mock 验证码正确  
165 - when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(reqVO.getCode());  
166 - // mock 抛出异常  
167 - when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword())))  
168 - .thenThrow(new DisabledException("测试用户被禁用"));  
169 -  
170 // 调用, 并断言异常 155 // 调用, 并断言异常
171 - assertServiceException(() -> authService.login(reqVO, userIp, userAgent), AUTH_LOGIN_USER_DISABLED); 156 + assertServiceException(() -> authService.verifyCaptcha(reqVO), AUTH_LOGIN_CAPTCHA_NOT_FOUND);
172 // 校验调用参数 157 // 校验调用参数
173 - verify(captchaService, times(1)).deleteCaptchaCode(reqVO.getUuid());  
174 verify(loginLogService, times(1)).createLoginLog( 158 verify(loginLogService, times(1)).createLoginLog(
175 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) 159 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
176 - && o.getResult().equals(LoginResultEnum.USER_DISABLED.getResult())) 160 + && o.getResult().equals(LoginResultEnum.CAPTCHA_NOT_FOUND.getResult()))
177 ); 161 );
178 } 162 }
179 163
180 @Test 164 @Test
181 - public void testLogin_unknownError() { 165 + public void testCaptcha_codeError() {
182 // 准备参数 166 // 准备参数
183 - String userIp = randomString();  
184 - String userAgent = randomString();  
185 AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); 167 AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class);
186 - // mock 验证码正确  
187 - when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(reqVO.getCode());  
188 - // mock 抛出异常  
189 - when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword())))  
190 - .thenThrow(new AuthenticationException("测试未知异常") {}); 168 +
  169 + // mock 验证码不正确
  170 + String code = randomString();
  171 + when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(code);
191 172
192 // 调用, 并断言异常 173 // 调用, 并断言异常
193 - assertServiceException(() -> authService.login(reqVO, userIp, userAgent), AUTH_LOGIN_FAIL_UNKNOWN); 174 + assertServiceException(() -> authService.verifyCaptcha(reqVO), AUTH_LOGIN_CAPTCHA_CODE_ERROR);
194 // 校验调用参数 175 // 校验调用参数
195 - verify(captchaService, times(1)).deleteCaptchaCode(reqVO.getUuid());  
196 - verify(loginLogService, times(1)).createLoginLog( 176 + verify(loginLogService).createLoginLog(
197 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) 177 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
198 - && o.getResult().equals(LoginResultEnum.UNKNOWN_ERROR.getResult())) 178 + && o.getResult().equals(LoginResultEnum.CAPTCHA_CODE_ERROR.getResult()))
199 ); 179 );
200 } 180 }
201 181
@@ -204,29 +184,32 @@ public class AuthServiceImplTest extends BaseDbUnitTest { @@ -204,29 +184,32 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
204 // 准备参数 184 // 准备参数
205 String userIp = randomString(); 185 String userIp = randomString();
206 String userAgent = randomString(); 186 String userAgent = randomString();
207 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); 187 + AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class, o ->
  188 + o.setUsername("test_username").setPassword("test_password"));
208 189
209 // mock 验证码正确 190 // mock 验证码正确
210 when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(reqVO.getCode()); 191 when(captchaService.getCaptchaCode(reqVO.getUuid())).thenReturn(reqVO.getCode());
211 - // mock authentication  
212 - Long userId = randomLongId();  
213 - Set<Long> userRoleIds = randomSet(Long.class);  
214 - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(userId));  
215 - when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword())))  
216 - .thenReturn(authentication);  
217 - when(authentication.getPrincipal()).thenReturn(loginUser); 192 + // mock user 数据
  193 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername("test_username")
  194 + .setPassword("test_password").setStatus(CommonStatusEnum.ENABLE.getStatus()));
  195 + when(userService.getUserByUsername(eq("test_username"))).thenReturn(user);
  196 + // mock password 匹配
  197 + when(userService.isPasswordMatch(eq("test_password"), eq(user.getPassword()))).thenReturn(true);
218 // mock 缓存登录用户到 Redis 198 // mock 缓存登录用户到 Redis
219 String token = randomString(); 199 String token = randomString();
220 - when(userSessionService.createUserSession(loginUser, userIp, userAgent)).thenReturn(token); 200 + when(userSessionService.createUserSession(argThat(argument -> {
  201 + AssertUtils.assertPojoEquals(user, argument);
  202 + return true;
  203 + }), eq(userIp), eq(userAgent))).thenReturn(token);
221 204
222 // 调用, 并断言异常 205 // 调用, 并断言异常
223 - String login = authService.login(reqVO, userIp, userAgent);  
224 - assertEquals(token, login); 206 + String result = authService.login(reqVO, userIp, userAgent);
  207 + assertEquals(token, result);
225 // 校验调用参数 208 // 校验调用参数
226 - verify(captchaService, times(1)).deleteCaptchaCode(reqVO.getUuid());  
227 - verify(loginLogService, times(1)).createLoginLog( 209 + verify(loginLogService).createLoginLog(
228 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) 210 argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType())
229 - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) 211 + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())
  212 + && o.getUserId().equals(user.getId()))
230 ); 213 );
231 } 214 }
232 215