From 5e8648508e11fa7fd72066396078944c24a18669 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 8 May 2022 02:33:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4=20Spring=20Security=20?= =?UTF-8?q?=E7=9A=84=20Member=20=E7=9A=84=20loadUsername=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E8=87=AA=E5=B7=B1=E5=AE=9A=E4=B9=89=E7=9A=84=20login0?= =?UTF-8?q?=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../YudaoSecurityAutoConfiguration.java | 19 +-- .../YudaoWebSecurityConfigurerAdapter.java | 18 +-- ...ultiUserDetailsAuthenticationProvider.java | 128 ------------------ ...tiUsernamePasswordAuthenticationToken.java | 43 ------ .../authentication/SpringSecurityUser.java | 78 ----------- .../filter/TokenAuthenticationFilter.java | 5 +- .../member/enums/ErrorCodeConstants.java | 1 - .../app/auth/AppAuthController.http | 2 +- .../member/convert/auth/AuthConvert.java | 7 - .../service/auth/MemberAuthService.java | 3 +- .../service/auth/MemberAuthServiceImpl.java | 88 ++++-------- .../service/user/MemberUserService.java | 9 ++ .../service/user/MemberUserServiceImpl.java | 17 ++- .../service/auth/MemberAuthServiceTest.java | 5 +- .../system/convert/auth/AuthConvert.java | 3 - .../system/service/auth/AdminAuthService.java | 2 +- .../service/auth/AdminAuthServiceImpl.java | 18 +-- 17 files changed, 63 insertions(+), 383 deletions(-) delete mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUsernamePasswordAuthenticationToken.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/SpringSecurityUser.java diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java index af728045c..087edc32f 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java @@ -1,13 +1,10 @@ package cn.iocoder.yudao.framework.security.config; import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect; -import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy; import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; -import cn.iocoder.yudao.framework.web.config.WebProperties; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -20,7 +17,6 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; import javax.annotation.Resource; -import java.util.List; /** * Spring Security 自动配置类,主要用于相关组件的配置 @@ -76,19 +72,8 @@ public class YudaoSecurityAutoConfiguration { * Token 认证过滤器 Bean */ @Bean - public TokenAuthenticationFilter authenticationTokenFilter(MultiUserDetailsAuthenticationProvider authenticationProvider, - GlobalExceptionHandler globalExceptionHandler) { - return new TokenAuthenticationFilter(securityProperties, authenticationProvider, globalExceptionHandler); - } - - /** - * 身份验证的 Provider Bean,通过它实现账号 + 密码的认证 - */ - @Bean - public MultiUserDetailsAuthenticationProvider authenticationProvider( - List securityFrameworkServices, - WebProperties webProperties, PasswordEncoder passwordEncoder) { - return new MultiUserDetailsAuthenticationProvider(securityFrameworkServices, webProperties, passwordEncoder); + public TokenAuthenticationFilter authenticationTokenFilter(GlobalExceptionHandler globalExceptionHandler) { + return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler); } /** diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java index c0bc2a056..61edba6e8 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.framework.security.config; -import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; import cn.iocoder.yudao.framework.web.config.WebProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -8,7 +7,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @@ -32,8 +30,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap @Resource private WebProperties webProperties; - @Resource - private MultiUserDetailsAuthenticationProvider authenticationProvider; /** * 认证失败处理类 Bean */ @@ -69,14 +65,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap return super.authenticationManagerBean(); } - /** - * 身份认证接口 - */ - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.authenticationProvider(authenticationProvider); - } - /** * 配置 URL 的安全配置 * @@ -130,11 +118,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap // 添加 JWT Filter httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } - - private String buildAdminApi(String url) { - return webProperties.getAdminApi().getPrefix() + url; - } - + private String buildAppApi(String url) { return webProperties.getAppApi().getPrefix() + url; } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java deleted file mode 100644 index 416e196d6..000000000 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java +++ /dev/null @@ -1,128 +0,0 @@ -package cn.iocoder.yudao.framework.security.core.authentication; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; -import cn.iocoder.yudao.framework.web.config.WebProperties; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.crypto.password.PasswordEncoder; - -import javax.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 支持多用户类型的 AuthenticationProvider 实现类 - * - * 为什么不用 {@link org.springframework.security.authentication.ProviderManager} 呢? - * 原因是,需要每个用户类型实现对应的 {@link AuthenticationProvider} + authentication,略显麻烦。实际,也是可以实现的。 - * - * 另外,额外支持 verifyTokenAndRefresh 校验令牌、logout 登出、mockLogin 模拟登陆等操作。 - * 实际上,它就是 {@link SecurityAuthFrameworkService} 定义的三个接口。 - * 因为需要支持多种类型,所以需要根据请求的 URL,判断出对应的用户类型,从而使用对应的 SecurityAuthFrameworkService 是吸纳 - * - * @see cn.iocoder.yudao.framework.common.enums.UserTypeEnum - * @author 芋道源码 - */ -public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { - - private final Map services = new HashMap<>(); - - private final WebProperties properties; - - private final PasswordEncoder passwordEncoder; - - public MultiUserDetailsAuthenticationProvider(List serviceList, - WebProperties properties, PasswordEncoder passwordEncoder) { - serviceList.forEach(service -> services.put(service.getUserType(), service)); - this.properties = properties; - this.passwordEncoder = passwordEncoder; - } - - // ========== AuthenticationProvider 相关 ========== - - @Override - protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { - // 执行用户的加载 - return selectService(authentication).loadUserByUsername(username); - } - - private SecurityAuthFrameworkService selectService(UsernamePasswordAuthenticationToken authentication) { - // 第一步,获得用户类型 - UserTypeEnum userType = getUserType(authentication); - // 第二步,获得 SecurityAuthFrameworkService - SecurityAuthFrameworkService service = services.get(userType); - Assert.notNull(service, "用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", userType); - return service; - } - - private UserTypeEnum getUserType(UsernamePasswordAuthenticationToken authentication) { - Assert.isInstanceOf(MultiUsernamePasswordAuthenticationToken.class, authentication); - MultiUsernamePasswordAuthenticationToken multiAuthentication = (MultiUsernamePasswordAuthenticationToken) authentication; - UserTypeEnum userType = multiAuthentication.getUserType(); - Assert.notNull(userType, "用户类型不能为空"); - return userType; - } - - @Override // copy 自 DaoAuthenticationProvider 的 additionalAuthenticationChecks 方法 - protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { - // 校验 credentials - if (authentication.getCredentials() == null) { - this.logger.debug("Failed to authenticate since no credentials provided"); - throw new BadCredentialsException(this.messages.getMessage( - "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); - } - // 校验 password - String presentedPassword = authentication.getCredentials().toString(); - if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { - this.logger.debug("Failed to authenticate since password does not match stored value"); - throw new BadCredentialsException(this.messages.getMessage( - "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); - } - } - - // ========== SecurityAuthFrameworkService 相关 ========== - - /** - * 校验 token 的有效性,并获取用户信息 - * 通过后,刷新 token 的过期时间 - * - * @param request 请求 - * @param token token - * @return 用户信息 - */ - public LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token) { - return selectService(request).verifyTokenAndRefresh(token); - } - - private SecurityAuthFrameworkService selectService(HttpServletRequest request) { - // 第一步,获得用户类型 - UserTypeEnum userType = getUserType(request); - // 第二步,获得 SecurityAuthFrameworkService - SecurityAuthFrameworkService service = services.get(userType); - Assert.notNull(service, "URI({}) 用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", - request.getRequestURI(), userType); - return service; - } - - private UserTypeEnum getUserType(HttpServletRequest request) { - if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) { - return UserTypeEnum.ADMIN; - } - if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) { - return UserTypeEnum.MEMBER; - } - throw new IllegalArgumentException(StrUtil.format("URI({}) 找不到匹配的用户类型", request.getRequestURI())); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUsernamePasswordAuthenticationToken.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUsernamePasswordAuthenticationToken.java deleted file mode 100644 index f0bc8dfac..000000000 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUsernamePasswordAuthenticationToken.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.framework.security.core.authentication; - -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import lombok.Getter; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; - -import java.util.Collection; - -/** - * 支持多用户的 UsernamePasswordAuthenticationToken 实现类 - * - * @author 芋道源码 - */ -@Getter -public class MultiUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { - - /** - * 用户类型 - */ - private UserTypeEnum userType; - - public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials) { - super(principal, credentials); - } - - public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, - Collection authorities) { - super(principal, credentials, authorities); - } - - public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, UserTypeEnum userType) { - super(principal, credentials); - this.userType = userType; - } - - public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, - Collection authorities, UserTypeEnum userType) { - super(principal, credentials, authorities); - this.userType = userType; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/SpringSecurityUser.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/SpringSecurityUser.java deleted file mode 100644 index 67b0c5ea6..000000000 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/SpringSecurityUser.java +++ /dev/null @@ -1,78 +0,0 @@ -package cn.iocoder.yudao.framework.security.core.authentication; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import lombok.AllArgsConstructor; -import lombok.Data; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Collection; -import java.util.Collections; - -/** - * 登录用户信息 - * - * @author 芋道源码 - */ -@Data -@AllArgsConstructor -public class SpringSecurityUser implements UserDetails { - - /** - * 用户编号 - */ - private Long id; - - /** - * 用户名 - */ - private String username; - /** - * 密码 - */ - private String password; - /** - * 状态 - */ - private Integer status; - /** - * 租户编号 - */ - private Long tenantId; - - @Override - public String getPassword() { - return password; - } - - @Override - public String getUsername() { - return username; - } - - @Override - public boolean isEnabled() { - return CommonStatusEnum.ENABLE.getStatus().equals(status); - } - - @Override - public Collection getAuthorities() { - return Collections.emptyList(); - } - - @Override - public boolean isAccountNonExpired() { - return true; // 返回 true,不依赖 Spring Security 判断 - } - - @Override - public boolean isAccountNonLocked() { - return true; // 返回 true,不依赖 Spring Security 判断 - } - - @Override - public boolean isCredentialsNonExpired() { - return true; // 返回 true,不依赖 Spring Security 判断 - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java index cf0ee7a23..b27863f60 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.security.config.SecurityProperties; import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; @@ -29,8 +28,6 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { private final SecurityProperties securityProperties; - private final MultiUserDetailsAuthenticationProvider authenticationProvider; - private final GlobalExceptionHandler globalExceptionHandler; @Override @@ -42,7 +39,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { Integer userType = WebFrameworkUtils.getLoginUserType(request); try { // 验证 token 有效性 - LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token); + LoginUser loginUser = null; // TODO 芋艿:待实现 // 模拟 Login 功能,方便日常开发调试 if (loginUser == null) { loginUser = mockLoginUser(request, token, userType); diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java index 9970c1ade..8b4380ca1 100644 --- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java +++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java @@ -17,7 +17,6 @@ public interface ErrorCodeConstants { // ========== AUTH 模块 1004003000 ========== ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确"); ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1004003001, "登录失败,账号被禁用"); - ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1004003002, "登录失败"); // 登录失败的兜底,未知原因 ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1004003004, "Token 已经过期"); ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1004003005, "未绑定账号,需要进行绑定"); diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http index 7a10c7754..210514699 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http @@ -1,5 +1,5 @@ ### 请求 /login 接口 => 成功 -POST {{appApi}}/member/login +POST {{appApi}}/member/auth/login Content-Type: application/json tenant-id: {{appTenentId}} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java index f33f85e70..9100c16e1 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java @@ -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); diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java index f7abd8622..6ded902c8 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java @@ -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 { /** * 手机 + 密码登录 diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java index c58a6d74d..efcc7be5d 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -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; + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java index 3c0e62de8..3b63c8d71 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java @@ -69,4 +69,13 @@ public interface MemberUserService { */ void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO); + /** + * 判断密码是否匹配 + * + * @param rawPassword 未加密的密码 + * @param encodedPassword 加密后的密码 + * @return 是否匹配 + */ + boolean isPasswordMatch(String rawPassword, String encodedPassword); + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java index 0522e8eda..ff91b0781 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java @@ -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) { diff --git a/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java b/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java index a982f9625..a3a43b2d2 100644 --- a/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java +++ b/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java @@ -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 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java index 8a93e645c..fdea4063f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.convert.auth; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.authentication.SpringSecurityUser; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; @@ -24,8 +23,6 @@ public interface AuthConvert { LoginUser convert(AdminUserDO bean); - SpringSecurityUser convert2(AdminUserDO user); - default AuthPermissionInfoRespVO convert(AdminUserDO user, List roleList, List menuList) { return AuthPermissionInfoRespVO.builder() .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build()) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java index 389e1a835..cf01334e8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java @@ -12,7 +12,7 @@ import javax.validation.Valid; * * @author 芋道源码 */ -public interface AdminAuthService extends SecurityAuthFrameworkService { +public interface AdminAuthService { /** * 账号登录 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index a0c6989d1..d049d9edb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -21,8 +21,6 @@ import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -226,11 +224,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { createLogoutLog(loginUser.getId()); } - @Override - public UserTypeEnum getUserType() { - return UserTypeEnum.ADMIN; - } - private void createLogoutLog(Long userId) { LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); reqDTO.setLogType(LoginLogTypeEnum.LOGOUT_SELF.getType()); @@ -244,11 +237,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { loginLogService.createLoginLog(reqDTO); } - @Override - public LoginUser verifyTokenAndRefresh(String token) { - return userSessionService.getLoginUser(token); - } - private LoginUser buildLoginUser(AdminUserDO user) { return AuthConvert.INSTANCE.convert(user).setUserType(getUserType().getValue()); } @@ -261,8 +249,8 @@ public class AdminAuthServiceImpl implements AdminAuthService { return user != null ? user.getUsername() : null; } - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return null; + private UserTypeEnum getUserType() { + return UserTypeEnum.ADMIN; } + }