Commit e9efff7076f66305b5bc80ee416a32ee7487b6dc
1 parent
928b7dbe
多模块重构 3:security 实现多用户的认证支持
Showing
23 changed files
with
279 additions
and
184 deletions
http-client.env.json
| @@ -2,6 +2,10 @@ | @@ -2,6 +2,10 @@ | ||
| 2 | "local": { | 2 | "local": { |
| 3 | "baseUrl": "http://127.0.0.1:48080/api", | 3 | "baseUrl": "http://127.0.0.1:48080/api", |
| 4 | "userServerUrl": "http://127.0.0.1:28080/api", | 4 | "userServerUrl": "http://127.0.0.1:28080/api", |
| 5 | - "token": "test1" | 5 | + "token": "test1", |
| 6 | + | ||
| 7 | + "userApi": "http://127.0.0.1:48080/app-api", | ||
| 8 | + "userToken": "test1", | ||
| 9 | + "userTenentId": "1" | ||
| 6 | } | 10 | } |
| 7 | } | 11 | } |
pom.xml
| @@ -14,7 +14,6 @@ | @@ -14,7 +14,6 @@ | ||
| 14 | <module>yudao-user-server</module> | 14 | <module>yudao-user-server</module> |
| 15 | <module>yudao-core-service</module> | 15 | <module>yudao-core-service</module> |
| 16 | <module>yudao-module-member</module> | 16 | <module>yudao-module-member</module> |
| 17 | - <module>yudao-server</module> | ||
| 18 | </modules> | 17 | </modules> |
| 19 | 18 | ||
| 20 | <name>${artifactId}</name> | 19 | <name>${artifactId}</name> |
yudao-admin-server/pom.xml
| @@ -13,7 +13,11 @@ | @@ -13,7 +13,11 @@ | ||
| 13 | <packaging>jar</packaging> | 13 | <packaging>jar</packaging> |
| 14 | 14 | ||
| 15 | <name>yudao-admin-server</name> | 15 | <name>yudao-admin-server</name> |
| 16 | - <description>管理后台 Server,提供其 API 接口</description> | 16 | + <description> |
| 17 | + 后端 Server 的主项目,通过引入需要 yudao-module-xxx 的依赖, | ||
| 18 | + 从而实现提供 RESTful API 给 yudao-ui-admin、yudao-ui-user 等前端项目。 | ||
| 19 | + 本质上来说,它就是个空壳(容器)! | ||
| 20 | + </description> | ||
| 17 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> | 21 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 18 | 22 | ||
| 19 | <dependencies> | 23 | <dependencies> |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/security/SecurityConfiguration.java
| @@ -33,7 +33,7 @@ public class SecurityConfiguration { | @@ -33,7 +33,7 @@ public class SecurityConfiguration { | ||
| 33 | registry.antMatchers(buildAdminApi("/system/sms/callback/**")).anonymous(); | 33 | registry.antMatchers(buildAdminApi("/system/sms/callback/**")).anonymous(); |
| 34 | 34 | ||
| 35 | // 设置 App API 无需认证 | 35 | // 设置 App API 无需认证 |
| 36 | - registry.antMatchers(buildAppApi("/**")); | 36 | + registry.antMatchers(buildAppApi("/**")).permitAll(); |
| 37 | }; | 37 | }; |
| 38 | } | 38 | } |
| 39 | 39 |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
| @@ -26,6 +26,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | @@ -26,6 +26,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 26 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | 26 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; |
| 27 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 27 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 28 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 28 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 29 | +import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken; | ||
| 29 | import lombok.extern.slf4j.Slf4j; | 30 | import lombok.extern.slf4j.Slf4j; |
| 30 | import me.zhyd.oauth.model.AuthUser; | 31 | import me.zhyd.oauth.model.AuthUser; |
| 31 | import org.springframework.context.annotation.Lazy; | 32 | import org.springframework.context.annotation.Lazy; |
| @@ -154,7 +155,8 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -154,7 +155,8 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 154 | try { | 155 | try { |
| 155 | // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 | 156 | // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 |
| 156 | // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 | 157 | // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 |
| 157 | - authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); | 158 | + authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken( |
| 159 | + username, password, getUserType())); | ||
| 158 | // org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username); | 160 | // org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username); |
| 159 | } catch (BadCredentialsException badCredentialsException) { | 161 | } catch (BadCredentialsException badCredentialsException) { |
| 160 | this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS); | 162 | this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS); |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/UserTypeEnum.java
| 1 | package cn.iocoder.yudao.framework.common.enums; | 1 | package cn.iocoder.yudao.framework.common.enums; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Matcher; | ||
| 4 | +import cn.hutool.core.util.ArrayUtil; | ||
| 3 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Getter; | 6 | import lombok.Getter; |
| 5 | 7 | ||
| @@ -22,4 +24,8 @@ public enum UserTypeEnum { | @@ -22,4 +24,8 @@ public enum UserTypeEnum { | ||
| 22 | */ | 24 | */ |
| 23 | private final String name; | 25 | private final String name; |
| 24 | 26 | ||
| 27 | + public static UserTypeEnum valueOf(Integer value) { | ||
| 28 | + return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values()); | ||
| 29 | + } | ||
| 30 | + | ||
| 25 | } | 31 | } |
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java
| @@ -149,6 +149,7 @@ public class OperateLogAspect { | @@ -149,6 +149,7 @@ public class OperateLogAspect { | ||
| 149 | 149 | ||
| 150 | private static void fillUserFields(OperateLogCreateReqDTO operateLogDTO) { | 150 | private static void fillUserFields(OperateLogCreateReqDTO operateLogDTO) { |
| 151 | operateLogDTO.setUserId(WebFrameworkUtils.getLoginUserId()); | 151 | operateLogDTO.setUserId(WebFrameworkUtils.getLoginUserId()); |
| 152 | + operateLogDTO.setUserType(WebFrameworkUtils.getLoginUserType()); | ||
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | private static void fillModuleFields(OperateLogCreateReqDTO operateLogDTO, | 155 | private static void fillModuleFields(OperateLogCreateReqDTO operateLogDTO, |
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java
| @@ -21,6 +21,9 @@ public class OperateLogCreateReqDTO { | @@ -21,6 +21,9 @@ public class OperateLogCreateReqDTO { | ||
| 21 | @ApiModelProperty(value = "用户编号", required = true, example = "1024") | 21 | @ApiModelProperty(value = "用户编号", required = true, example = "1024") |
| 22 | @NotNull(message = "用户编号不能为空") | 22 | @NotNull(message = "用户编号不能为空") |
| 23 | private Long userId; | 23 | private Long userId; |
| 24 | + @ApiModelProperty(value = "用户类型", required = true, example = "1") | ||
| 25 | + @NotNull(message = "用户类型不能为空") | ||
| 26 | + private Integer userType; | ||
| 24 | 27 | ||
| 25 | @ApiModelProperty(value = "操作模块", required = true, example = "订单") | 28 | @ApiModelProperty(value = "操作模块", required = true, example = "订单") |
| 26 | @NotEmpty(message = "操作模块不能为空") | 29 | @NotEmpty(message = "操作模块不能为空") |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
| 1 | package cn.iocoder.yudao.framework.security.config; | 1 | package cn.iocoder.yudao.framework.security.config; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect; | 3 | import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect; |
| 4 | +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; | ||
| 4 | import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy; | 5 | import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy; |
| 5 | import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter; | 6 | import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter; |
| 6 | import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; | 7 | import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; |
| 7 | import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; | 8 | import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; |
| 8 | import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl; | 9 | import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl; |
| 9 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; | 10 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; |
| 10 | -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthService; | ||
| 11 | -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthServiceImpl; | ||
| 12 | import cn.iocoder.yudao.framework.web.config.WebProperties; | 11 | import cn.iocoder.yudao.framework.web.config.WebProperties; |
| 13 | import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; | 12 | import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; |
| 14 | import org.springframework.beans.factory.config.MethodInvokingFactoryBean; | 13 | import org.springframework.beans.factory.config.MethodInvokingFactoryBean; |
| @@ -68,8 +67,8 @@ public class YudaoSecurityAutoConfiguration { | @@ -68,8 +67,8 @@ public class YudaoSecurityAutoConfiguration { | ||
| 68 | * 退出处理类 Bean | 67 | * 退出处理类 Bean |
| 69 | */ | 68 | */ |
| 70 | @Bean | 69 | @Bean |
| 71 | - public LogoutSuccessHandler logoutSuccessHandler(SecurityAuthService securityAuthService) { | ||
| 72 | - return new LogoutSuccessHandlerImpl(securityProperties, securityAuthService); | 70 | + public LogoutSuccessHandler logoutSuccessHandler(MultiUserDetailsAuthenticationProvider authenticationProvider) { |
| 71 | + return new LogoutSuccessHandlerImpl(securityProperties, authenticationProvider); | ||
| 73 | } | 72 | } |
| 74 | 73 | ||
| 75 | /** | 74 | /** |
| @@ -87,18 +86,19 @@ public class YudaoSecurityAutoConfiguration { | @@ -87,18 +86,19 @@ public class YudaoSecurityAutoConfiguration { | ||
| 87 | * Token 认证过滤器 Bean | 86 | * Token 认证过滤器 Bean |
| 88 | */ | 87 | */ |
| 89 | @Bean | 88 | @Bean |
| 90 | - public JWTAuthenticationTokenFilter authenticationTokenFilter(SecurityAuthService securityAuthService, | 89 | + public JWTAuthenticationTokenFilter authenticationTokenFilter(MultiUserDetailsAuthenticationProvider authenticationProvider, |
| 91 | GlobalExceptionHandler globalExceptionHandler) { | 90 | GlobalExceptionHandler globalExceptionHandler) { |
| 92 | - return new JWTAuthenticationTokenFilter(securityProperties, securityAuthService, globalExceptionHandler); | 91 | + return new JWTAuthenticationTokenFilter(securityProperties, authenticationProvider, globalExceptionHandler); |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | /** | 94 | /** |
| 96 | - * 安全认证的 Service Bean | 95 | + * 身份验证的 Provider Bean,通过它实现账号 + 密码的认证 |
| 97 | */ | 96 | */ |
| 98 | @Bean | 97 | @Bean |
| 99 | - public SecurityAuthService securityAuthService(List<SecurityAuthFrameworkService> securityFrameworkServices, | ||
| 100 | - WebProperties webProperties) { | ||
| 101 | - return new SecurityAuthServiceImpl(securityFrameworkServices, webProperties); | 98 | + public MultiUserDetailsAuthenticationProvider authenticationProvider( |
| 99 | + List<SecurityAuthFrameworkService> securityFrameworkServices, | ||
| 100 | + WebProperties webProperties, PasswordEncoder passwordEncoder) { | ||
| 101 | + return new MultiUserDetailsAuthenticationProvider(securityFrameworkServices, webProperties, passwordEncoder); | ||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | /** | 104 | /** |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
| 1 | package cn.iocoder.yudao.framework.security.config; | 1 | package cn.iocoder.yudao.framework.security.config; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; | ||
| 3 | import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter; | 4 | import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter; |
| 4 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; | 5 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; |
| 5 | import cn.iocoder.yudao.framework.web.config.WebProperties; | 6 | import cn.iocoder.yudao.framework.web.config.WebProperties; |
| @@ -35,16 +36,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap | @@ -35,16 +36,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap | ||
| 35 | @Resource | 36 | @Resource |
| 36 | private WebProperties webProperties; | 37 | private WebProperties webProperties; |
| 37 | 38 | ||
| 38 | - /** | ||
| 39 | - * 自定义用户【认证】逻辑 | ||
| 40 | - */ | ||
| 41 | - @Resource | ||
| 42 | - private SecurityAuthFrameworkService userDetailsService; | ||
| 43 | - /** | ||
| 44 | - * Spring Security 加密器 | ||
| 45 | - */ | ||
| 46 | @Resource | 39 | @Resource |
| 47 | - private PasswordEncoder passwordEncoder; | 40 | + private MultiUserDetailsAuthenticationProvider authenticationProvider; |
| 48 | /** | 41 | /** |
| 49 | * 认证失败处理类 Bean | 42 | * 认证失败处理类 Bean |
| 50 | */ | 43 | */ |
| @@ -91,8 +84,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap | @@ -91,8 +84,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap | ||
| 91 | */ | 84 | */ |
| 92 | @Override | 85 | @Override |
| 93 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { | 86 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { |
| 94 | - auth | ||
| 95 | - .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); | 87 | + auth.authenticationProvider(authenticationProvider); |
| 96 | } | 88 | } |
| 97 | 89 | ||
| 98 | /** | 90 | /** |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUserDetailsAuthenticationProvider.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.security.core.authentication; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 6 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 7 | +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; | ||
| 8 | +import cn.iocoder.yudao.framework.web.config.WebProperties; | ||
| 9 | +import org.springframework.security.authentication.AuthenticationProvider; | ||
| 10 | +import org.springframework.security.authentication.BadCredentialsException; | ||
| 11 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
| 12 | +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; | ||
| 13 | +import org.springframework.security.core.AuthenticationException; | ||
| 14 | +import org.springframework.security.core.userdetails.UserDetails; | ||
| 15 | +import org.springframework.security.crypto.password.PasswordEncoder; | ||
| 16 | + | ||
| 17 | +import javax.servlet.http.HttpServletRequest; | ||
| 18 | +import java.util.HashMap; | ||
| 19 | +import java.util.List; | ||
| 20 | +import java.util.Map; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 支持多用户类型的 AuthenticationProvider 实现类 | ||
| 24 | + * | ||
| 25 | + * 为什么不用 {@link org.springframework.security.authentication.ProviderManager} 呢? | ||
| 26 | + * 原因是,需要每个用户类型实现对应的 {@link AuthenticationProvider} + authentication,略显麻烦。实际,也是可以实现的。 | ||
| 27 | + * | ||
| 28 | + * 另外,额外支持 verifyTokenAndRefresh 校验令牌、logout 登出、mockLogin 模拟登陆等操作。 | ||
| 29 | + * 实际上,它就是 {@link SecurityAuthFrameworkService} 定义的三个接口。 | ||
| 30 | + * 因为需要支持多种类型,所以需要根据请求的 URL,判断出对应的用户类型,从而使用对应的 SecurityAuthFrameworkService 是吸纳 | ||
| 31 | + * | ||
| 32 | + * @see cn.iocoder.yudao.framework.common.enums.UserTypeEnum | ||
| 33 | + * @author 芋道源码 | ||
| 34 | + */ | ||
| 35 | +public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { | ||
| 36 | + | ||
| 37 | + private final Map<UserTypeEnum, SecurityAuthFrameworkService> services = new HashMap<>(); | ||
| 38 | + | ||
| 39 | + private final WebProperties properties; | ||
| 40 | + | ||
| 41 | + private final PasswordEncoder passwordEncoder; | ||
| 42 | + | ||
| 43 | + public MultiUserDetailsAuthenticationProvider(List<SecurityAuthFrameworkService> serviceList, | ||
| 44 | + WebProperties properties, PasswordEncoder passwordEncoder) { | ||
| 45 | + serviceList.forEach(service -> services.put(service.getUserType(), service)); | ||
| 46 | + this.properties = properties; | ||
| 47 | + this.passwordEncoder = passwordEncoder; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // ========== AuthenticationProvider 相关 ========== | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) | ||
| 54 | + throws AuthenticationException { | ||
| 55 | + // 执行用户的加载 | ||
| 56 | + return selectService(authentication).loadUserByUsername(username); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + private SecurityAuthFrameworkService selectService(UsernamePasswordAuthenticationToken authentication) { | ||
| 60 | + // 第一步,获得用户类型 | ||
| 61 | + UserTypeEnum userType = getUserType(authentication); | ||
| 62 | + // 第二步,获得 SecurityAuthFrameworkService | ||
| 63 | + SecurityAuthFrameworkService service = services.get(userType); | ||
| 64 | + Assert.notNull(service, "用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", userType); | ||
| 65 | + return service; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + private UserTypeEnum getUserType(UsernamePasswordAuthenticationToken authentication) { | ||
| 69 | + Assert.isInstanceOf(MultiUsernamePasswordAuthenticationToken.class, authentication); | ||
| 70 | + MultiUsernamePasswordAuthenticationToken multiAuthentication = (MultiUsernamePasswordAuthenticationToken) authentication; | ||
| 71 | + UserTypeEnum userType = multiAuthentication.getUserType(); | ||
| 72 | + Assert.notNull(userType, "用户类型不能为空"); | ||
| 73 | + return userType; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + @Override // copy 自 DaoAuthenticationProvider 的 additionalAuthenticationChecks 方法 | ||
| 77 | + protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) | ||
| 78 | + throws AuthenticationException { | ||
| 79 | + // 校验 credentials | ||
| 80 | + if (authentication.getCredentials() == null) { | ||
| 81 | + this.logger.debug("Failed to authenticate since no credentials provided"); | ||
| 82 | + throw new BadCredentialsException(this.messages.getMessage( | ||
| 83 | + "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); | ||
| 84 | + } | ||
| 85 | + // 校验 password | ||
| 86 | + String presentedPassword = authentication.getCredentials().toString(); | ||
| 87 | + if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { | ||
| 88 | + this.logger.debug("Failed to authenticate since password does not match stored value"); | ||
| 89 | + throw new BadCredentialsException(this.messages.getMessage( | ||
| 90 | + "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + // ========== SecurityAuthFrameworkService 相关 ========== | ||
| 95 | + | ||
| 96 | + /** | ||
| 97 | + * 校验 token 的有效性,并获取用户信息 | ||
| 98 | + * 通过后,刷新 token 的过期时间 | ||
| 99 | + * | ||
| 100 | + * @param request 请求 | ||
| 101 | + * @param token token | ||
| 102 | + * @return 用户信息 | ||
| 103 | + */ | ||
| 104 | + public LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token) { | ||
| 105 | + return selectService(request).verifyTokenAndRefresh(token); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + /** | ||
| 109 | + * 模拟指定用户编号的 LoginUser | ||
| 110 | + * | ||
| 111 | + * @param request 请求 | ||
| 112 | + * @param userId 用户编号 | ||
| 113 | + * @return 登录用户 | ||
| 114 | + */ | ||
| 115 | + public LoginUser mockLogin(HttpServletRequest request, Long userId) { | ||
| 116 | + return selectService(request).mockLogin(userId); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + /** | ||
| 120 | + * 基于 token 退出登录 | ||
| 121 | + * | ||
| 122 | + * @param request 请求 | ||
| 123 | + * @param token token | ||
| 124 | + */ | ||
| 125 | + public void logout(HttpServletRequest request, String token) { | ||
| 126 | + selectService(request).logout(token); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + private SecurityAuthFrameworkService selectService(HttpServletRequest request) { | ||
| 130 | + // 第一步,获得用户类型 | ||
| 131 | + UserTypeEnum userType = getUserType(request); | ||
| 132 | + // 第二步,获得 SecurityAuthFrameworkService | ||
| 133 | + SecurityAuthFrameworkService service = services.get(userType); | ||
| 134 | + Assert.notNull(service, "URI({}) 用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", | ||
| 135 | + request.getRequestURI(), userType); | ||
| 136 | + return service; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + private UserTypeEnum getUserType(HttpServletRequest request) { | ||
| 140 | + if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) { | ||
| 141 | + return UserTypeEnum.ADMIN; | ||
| 142 | + } | ||
| 143 | + if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) { | ||
| 144 | + return UserTypeEnum.MEMBER; | ||
| 145 | + } | ||
| 146 | + throw new IllegalArgumentException(StrUtil.format("URI({}) 找不到匹配的用户类型", request.getRequestURI())); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | +} |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/authentication/MultiUsernamePasswordAuthenticationToken.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.security.core.authentication; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 4 | +import lombok.Getter; | ||
| 5 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
| 6 | +import org.springframework.security.core.GrantedAuthority; | ||
| 7 | + | ||
| 8 | +import java.util.Collection; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 支持多用户的 UsernamePasswordAuthenticationToken 实现类 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Getter | ||
| 16 | +public class MultiUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 用户类型 | ||
| 20 | + */ | ||
| 21 | + private UserTypeEnum userType; | ||
| 22 | + | ||
| 23 | + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials) { | ||
| 24 | + super(principal, credentials); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, | ||
| 28 | + Collection<? extends GrantedAuthority> authorities) { | ||
| 29 | + super(principal, credentials, authorities); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, UserTypeEnum userType) { | ||
| 33 | + super(principal, credentials); | ||
| 34 | + this.userType = userType; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public MultiUsernamePasswordAuthenticationToken(Object principal, Object credentials, | ||
| 38 | + Collection<? extends GrantedAuthority> authorities, UserTypeEnum userType) { | ||
| 39 | + super(principal, credentials, authorities); | ||
| 40 | + this.userType = userType; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | +} |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JWTAuthenticationTokenFilter.java
| @@ -5,10 +5,10 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -5,10 +5,10 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 5 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 6 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; | 6 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| 7 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 7 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 8 | -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthService; | 8 | +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; |
| 9 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | 9 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 10 | import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; | 10 | import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; |
| 11 | -import lombok.AllArgsConstructor; | 11 | +import lombok.RequiredArgsConstructor; |
| 12 | import org.springframework.web.filter.OncePerRequestFilter; | 12 | import org.springframework.web.filter.OncePerRequestFilter; |
| 13 | 13 | ||
| 14 | import javax.servlet.FilterChain; | 14 | import javax.servlet.FilterChain; |
| @@ -23,12 +23,12 @@ import java.io.IOException; | @@ -23,12 +23,12 @@ import java.io.IOException; | ||
| 23 | * | 23 | * |
| 24 | * @author 芋道源码 | 24 | * @author 芋道源码 |
| 25 | */ | 25 | */ |
| 26 | -@AllArgsConstructor | 26 | +@RequiredArgsConstructor |
| 27 | public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { | 27 | public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { |
| 28 | 28 | ||
| 29 | private final SecurityProperties securityProperties; | 29 | private final SecurityProperties securityProperties; |
| 30 | 30 | ||
| 31 | - private final SecurityAuthService authService; | 31 | + private final MultiUserDetailsAuthenticationProvider authenticationProvider; |
| 32 | 32 | ||
| 33 | private final GlobalExceptionHandler globalExceptionHandler; | 33 | private final GlobalExceptionHandler globalExceptionHandler; |
| 34 | 34 | ||
| @@ -40,7 +40,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { | @@ -40,7 +40,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { | ||
| 40 | if (StrUtil.isNotEmpty(token)) { | 40 | if (StrUtil.isNotEmpty(token)) { |
| 41 | try { | 41 | try { |
| 42 | // 验证 token 有效性 | 42 | // 验证 token 有效性 |
| 43 | - LoginUser loginUser = authService.verifyTokenAndRefresh(request, token); | 43 | + LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token); |
| 44 | // 模拟 Login 功能,方便日常开发调试 | 44 | // 模拟 Login 功能,方便日常开发调试 |
| 45 | if (loginUser == null) { | 45 | if (loginUser == null) { |
| 46 | loginUser = this.mockLoginUser(request, token); | 46 | loginUser = this.mockLoginUser(request, token); |
| @@ -78,7 +78,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { | @@ -78,7 +78,7 @@ public class JWTAuthenticationTokenFilter extends OncePerRequestFilter { | ||
| 78 | return null; | 78 | return null; |
| 79 | } | 79 | } |
| 80 | Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length())); | 80 | Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length())); |
| 81 | - return authService.mockLogin(request, userId); | 81 | + return authenticationProvider.mockLogin(request, userId); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | } | 84 | } |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java
| @@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil; | @@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 5 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 6 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; | 6 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| 7 | -import cn.iocoder.yudao.framework.security.core.service.SecurityAuthService; | 7 | +import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; |
| 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 9 | import lombok.AllArgsConstructor; | 9 | import lombok.AllArgsConstructor; |
| 10 | import org.springframework.security.core.Authentication; | 10 | import org.springframework.security.core.Authentication; |
| @@ -24,14 +24,14 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { | @@ -24,14 +24,14 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { | ||
| 24 | 24 | ||
| 25 | private final SecurityProperties securityProperties; | 25 | private final SecurityProperties securityProperties; |
| 26 | 26 | ||
| 27 | - private final SecurityAuthService authService; | 27 | + private final MultiUserDetailsAuthenticationProvider authenticationProvider; |
| 28 | 28 | ||
| 29 | @Override | 29 | @Override |
| 30 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { | 30 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { |
| 31 | // 执行退出 | 31 | // 执行退出 |
| 32 | String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); | 32 | String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); |
| 33 | if (StrUtil.isNotBlank(token)) { | 33 | if (StrUtil.isNotBlank(token)) { |
| 34 | - authService.logout(request, token); | 34 | + authenticationProvider.logout(request, token); |
| 35 | } | 35 | } |
| 36 | // 返回成功 | 36 | // 返回成功 |
| 37 | ServletUtils.writeJSON(response, CommonResult.success(null)); | 37 | ServletUtils.writeJSON(response, CommonResult.success(null)); |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthService.java deleted
| 1 | -package cn.iocoder.yudao.framework.security.core.service; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 4 | - | ||
| 5 | -import javax.servlet.http.HttpServletRequest; | ||
| 6 | - | ||
| 7 | -/** | ||
| 8 | - * 安全认证的 Service 接口,对 security 组件提供统一的 Auth 相关的方法。 | ||
| 9 | - * 主要是会基于 {@link HttpServletRequest} 参数,匹配对应的 {@link SecurityAuthFrameworkService} 实现,然后调用其方法。 | ||
| 10 | - * 因此,在方法的定义上,和 {@link SecurityAuthFrameworkService} 差不多。 | ||
| 11 | - * | ||
| 12 | - * @author 芋道源码 | ||
| 13 | - */ | ||
| 14 | -public interface SecurityAuthService { | ||
| 15 | - | ||
| 16 | - /** | ||
| 17 | - * 校验 token 的有效性,并获取用户信息 | ||
| 18 | - * 通过后,刷新 token 的过期时间 | ||
| 19 | - * | ||
| 20 | - * @param request 请求 | ||
| 21 | - * @param token token | ||
| 22 | - * @return 用户信息 | ||
| 23 | - */ | ||
| 24 | - LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token); | ||
| 25 | - | ||
| 26 | - /** | ||
| 27 | - * 模拟指定用户编号的 LoginUser | ||
| 28 | - * | ||
| 29 | - * @param request 请求 | ||
| 30 | - * @param userId 用户编号 | ||
| 31 | - * @return 登录用户 | ||
| 32 | - */ | ||
| 33 | - LoginUser mockLogin(HttpServletRequest request, Long userId); | ||
| 34 | - | ||
| 35 | - /** | ||
| 36 | - * 基于 token 退出登录 | ||
| 37 | - * | ||
| 38 | - * @param request 请求 | ||
| 39 | - * @param token token | ||
| 40 | - */ | ||
| 41 | - void logout(HttpServletRequest request, String token); | ||
| 42 | - | ||
| 43 | -} |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityAuthServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.framework.security.core.service; | ||
| 2 | - | ||
| 3 | -import cn.hutool.core.lang.Assert; | ||
| 4 | -import cn.hutool.core.util.StrUtil; | ||
| 5 | -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 6 | -import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 7 | -import cn.iocoder.yudao.framework.web.config.WebProperties; | ||
| 8 | - | ||
| 9 | -import javax.servlet.http.HttpServletRequest; | ||
| 10 | -import java.util.HashMap; | ||
| 11 | -import java.util.List; | ||
| 12 | -import java.util.Map; | ||
| 13 | - | ||
| 14 | -/** | ||
| 15 | - * 安全认证的 Service 实现类,基于请求地址,计算到对应的 {@link UserTypeEnum} 枚举,从而拿到对应的 {@link SecurityAuthFrameworkService} 实现 | ||
| 16 | - * | ||
| 17 | - * @author 芋道源码 | ||
| 18 | - */ | ||
| 19 | -public class SecurityAuthServiceImpl implements SecurityAuthService { | ||
| 20 | - | ||
| 21 | - private final Map<UserTypeEnum, SecurityAuthFrameworkService> services = new HashMap<>(); | ||
| 22 | - private final WebProperties properties; | ||
| 23 | - | ||
| 24 | - public SecurityAuthServiceImpl(List<SecurityAuthFrameworkService> serviceList, WebProperties properties) { | ||
| 25 | - serviceList.forEach(service -> services.put(service.getUserType(), service)); | ||
| 26 | - this.properties = properties; | ||
| 27 | - } | ||
| 28 | - | ||
| 29 | - @Override | ||
| 30 | - public LoginUser verifyTokenAndRefresh(HttpServletRequest request, String token) { | ||
| 31 | - return selectService(request).verifyTokenAndRefresh(token); | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | - @Override | ||
| 35 | - public LoginUser mockLogin(HttpServletRequest request, Long userId) { | ||
| 36 | - return selectService(request).mockLogin(userId); | ||
| 37 | - } | ||
| 38 | - | ||
| 39 | - @Override | ||
| 40 | - public void logout(HttpServletRequest request, String token) { | ||
| 41 | - selectService(request).logout(token); | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - private SecurityAuthFrameworkService selectService(HttpServletRequest request) { | ||
| 45 | - // 第一步,获得用户类型 | ||
| 46 | - UserTypeEnum userType = getUserType(request); | ||
| 47 | - // 第二步,获得 SecurityAuthFrameworkService | ||
| 48 | - SecurityAuthFrameworkService service = services.get(userType); | ||
| 49 | - Assert.notNull(service, "URI({}) 用户类型({}) 找不到 SecurityAuthFrameworkService 实现类", | ||
| 50 | - request.getRequestURI(), userType); | ||
| 51 | - return service; | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - private UserTypeEnum getUserType(HttpServletRequest request) { | ||
| 55 | - if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) { | ||
| 56 | - return UserTypeEnum.ADMIN; | ||
| 57 | - } | ||
| 58 | - if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) { | ||
| 59 | - return UserTypeEnum.MEMBER; | ||
| 60 | - } | ||
| 61 | - throw new IllegalArgumentException(StrUtil.format("URI({}) 找不到匹配的用户类型", request.getRequestURI())); | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | -} |
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
| @@ -55,6 +55,11 @@ public class WebFrameworkUtils { | @@ -55,6 +55,11 @@ public class WebFrameworkUtils { | ||
| 55 | return (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE); | 55 | return (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | + public static Integer getLoginUserType() { | ||
| 59 | + HttpServletRequest request = getRequest(); | ||
| 60 | + return getLoginUserType(request); | ||
| 61 | + } | ||
| 62 | + | ||
| 58 | public static Long getLoginUserId() { | 63 | public static Long getLoginUserId() { |
| 59 | HttpServletRequest request = getRequest(); | 64 | HttpServletRequest request = getRequest(); |
| 60 | return getLoginUserId(request); | 65 | return getLoginUserId(request); |
yudao-module-member/yudao-module-member-impl/pom.xml
| @@ -32,6 +32,10 @@ | @@ -32,6 +32,10 @@ | ||
| 32 | 32 | ||
| 33 | <dependency> | 33 | <dependency> |
| 34 | <groupId>cn.iocoder.boot</groupId> | 34 | <groupId>cn.iocoder.boot</groupId> |
| 35 | + <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId> | ||
| 36 | + </dependency> | ||
| 37 | + <dependency> | ||
| 38 | + <groupId>cn.iocoder.boot</groupId> | ||
| 35 | <artifactId>yudao-spring-boot-starter-biz-sms</artifactId> | 39 | <artifactId>yudao-spring-boot-starter-biz-sms</artifactId> |
| 36 | </dependency> | 40 | </dependency> |
| 37 | <dependency> | 41 | <dependency> |
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth; | ||
| 3 | import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService; | 3 | import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService; |
| 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||
| 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | 7 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 7 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; | 8 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; |
| 8 | import cn.iocoder.yudao.module.member.service.auth.AuthService; | 9 | import cn.iocoder.yudao.module.member.service.auth.AuthService; |
| @@ -40,6 +41,7 @@ public class AppAuthController { | @@ -40,6 +41,7 @@ public class AppAuthController { | ||
| 40 | 41 | ||
| 41 | @PostMapping("/login") | 42 | @PostMapping("/login") |
| 42 | @ApiOperation("使用手机 + 密码登录") | 43 | @ApiOperation("使用手机 + 密码登录") |
| 44 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 43 | public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { | 45 | public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { |
| 44 | String token = authService.login(reqVO, getClientIP(), getUserAgent()); | 46 | String token = authService.login(reqVO, getClientIP(), getUserAgent()); |
| 45 | // 返回结果 | 47 | // 返回结果 |
| @@ -48,6 +50,7 @@ public class AppAuthController { | @@ -48,6 +50,7 @@ public class AppAuthController { | ||
| 48 | 50 | ||
| 49 | @PostMapping("/sms-login") | 51 | @PostMapping("/sms-login") |
| 50 | @ApiOperation("使用手机 + 验证码登录") | 52 | @ApiOperation("使用手机 + 验证码登录") |
| 53 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 51 | public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { | 54 | public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { |
| 52 | String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent()); | 55 | String token = authService.smsLogin(reqVO, getClientIP(), getUserAgent()); |
| 53 | // 返回结果 | 56 | // 返回结果 |
| @@ -56,12 +59,13 @@ public class AppAuthController { | @@ -56,12 +59,13 @@ public class AppAuthController { | ||
| 56 | 59 | ||
| 57 | @PostMapping("/send-sms-code") | 60 | @PostMapping("/send-sms-code") |
| 58 | @ApiOperation(value = "发送手机验证码") | 61 | @ApiOperation(value = "发送手机验证码") |
| 62 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 59 | public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid AppAuthSendSmsReqVO reqVO) { | 63 | public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid AppAuthSendSmsReqVO reqVO) { |
| 60 | smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); | 64 | smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); |
| 61 | return success(true); | 65 | return success(true); |
| 62 | } | 66 | } |
| 63 | 67 | ||
| 64 | - @GetMapping("/send-sms-code-login") | 68 | + @GetMapping("/send-sms-code-login") // TODO 芋艿:post 比较合理 |
| 65 | @ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用") | 69 | @ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用") |
| 66 | public CommonResult<Boolean> sendSmsCodeLogin() { | 70 | public CommonResult<Boolean> sendSmsCodeLogin() { |
| 67 | smsCodeService.sendSmsCodeLogin(getLoginUserId()); | 71 | smsCodeService.sendSmsCodeLogin(getLoginUserId()); |
| @@ -71,6 +75,7 @@ public class AppAuthController { | @@ -71,6 +75,7 @@ public class AppAuthController { | ||
| 71 | @PostMapping("/reset-password") | 75 | @PostMapping("/reset-password") |
| 72 | @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") | 76 | @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") |
| 73 | @PreAuthenticated | 77 | @PreAuthenticated |
| 78 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 74 | public CommonResult<Boolean> resetPassword(@RequestBody @Valid AppAuthResetPasswordReqVO reqVO) { | 79 | public CommonResult<Boolean> resetPassword(@RequestBody @Valid AppAuthResetPasswordReqVO reqVO) { |
| 75 | authService.resetPassword(reqVO); | 80 | authService.resetPassword(reqVO); |
| 76 | return success(true); | 81 | return success(true); |
| @@ -106,6 +111,7 @@ public class AppAuthController { | @@ -106,6 +111,7 @@ public class AppAuthController { | ||
| 106 | 111 | ||
| 107 | @PostMapping("/social-login2") | 112 | @PostMapping("/social-login2") |
| 108 | @ApiOperation("社交登录,使用 手机号 + 手机验证码") | 113 | @ApiOperation("社交登录,使用 手机号 + 手机验证码") |
| 114 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 109 | public CommonResult<AppAuthLoginRespVO> socialLogin2(@RequestBody @Valid AppAuthSocialLogin2ReqVO reqVO) { | 115 | public CommonResult<AppAuthLoginRespVO> socialLogin2(@RequestBody @Valid AppAuthSocialLogin2ReqVO reqVO) { |
| 110 | String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); | 116 | String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); |
| 111 | return success(AppAuthLoginRespVO.builder().token(token).build()); | 117 | return success(AppAuthLoginRespVO.builder().token(token).build()); |
| @@ -113,6 +119,7 @@ public class AppAuthController { | @@ -113,6 +119,7 @@ public class AppAuthController { | ||
| 113 | 119 | ||
| 114 | @PostMapping("/social-bind") | 120 | @PostMapping("/social-bind") |
| 115 | @ApiOperation("社交绑定,使用 code 授权码") | 121 | @ApiOperation("社交绑定,使用 code 授权码") |
| 122 | + @PreAuthenticated | ||
| 116 | public CommonResult<Boolean> socialBind(@RequestBody @Valid AppAuthSocialBindReqVO reqVO) { | 123 | public CommonResult<Boolean> socialBind(@RequestBody @Valid AppAuthSocialBindReqVO reqVO) { |
| 117 | authService.socialBind(getLoginUserId(), reqVO); | 124 | authService.socialBind(getLoginUserId(), reqVO); |
| 118 | return CommonResult.success(true); | 125 | return CommonResult.success(true); |
| @@ -120,6 +127,7 @@ public class AppAuthController { | @@ -120,6 +127,7 @@ public class AppAuthController { | ||
| 120 | 127 | ||
| 121 | @DeleteMapping("/social-unbind") | 128 | @DeleteMapping("/social-unbind") |
| 122 | @ApiOperation("取消社交绑定") | 129 | @ApiOperation("取消社交绑定") |
| 130 | + @PreAuthenticated | ||
| 123 | public CommonResult<Boolean> socialUnbind(@RequestBody AppAuthSocialUnbindReqVO reqVO) { | 131 | public CommonResult<Boolean> socialUnbind(@RequestBody AppAuthSocialUnbindReqVO reqVO) { |
| 124 | socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId(), UserTypeEnum.MEMBER); | 132 | socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId(), UserTypeEnum.MEMBER); |
| 125 | return CommonResult.success(true); | 133 | return CommonResult.success(true); |
yudao-module-member/yudao-module-member-impl/src/main/java/cn/iocoder/yudao/module/member/service/auth/AuthServiceImpl.java
| @@ -14,6 +14,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | @@ -14,6 +14,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 14 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | 14 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; |
| 15 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 15 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 16 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 16 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 17 | +import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken; | ||
| 17 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; | 18 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; |
| 18 | import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; | 19 | import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; |
| 19 | import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; | 20 | import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO; |
| @@ -176,7 +177,8 @@ public class AuthServiceImpl implements AuthService { | @@ -176,7 +177,8 @@ public class AuthServiceImpl implements AuthService { | ||
| 176 | try { | 177 | try { |
| 177 | // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 | 178 | // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证 |
| 178 | // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 | 179 | // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 |
| 179 | - authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); | 180 | + authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken( |
| 181 | + username, password, getUserType())); | ||
| 180 | } catch (BadCredentialsException badCredentialsException) { | 182 | } catch (BadCredentialsException badCredentialsException) { |
| 181 | this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS); | 183 | this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS); |
| 182 | throw exception(AUTH_LOGIN_BAD_CREDENTIALS); | 184 | throw exception(AUTH_LOGIN_BAD_CREDENTIALS); |
yudao-server/pom.xml deleted
| 1 | -<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | -<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 4 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| 5 | - <parent> | ||
| 6 | - <artifactId>yudao</artifactId> | ||
| 7 | - <groupId>cn.iocoder.boot</groupId> | ||
| 8 | - <version>${revision}</version> | ||
| 9 | - </parent> | ||
| 10 | - <modelVersion>4.0.0</modelVersion> | ||
| 11 | - | ||
| 12 | - <artifactId>yudao-server</artifactId> | ||
| 13 | - <packaging>jar</packaging> | ||
| 14 | - | ||
| 15 | - <name>${artifactId}</name> | ||
| 16 | - <description> | ||
| 17 | - 后端 Server 的主项目,通过引入需要 yudao-module-xxx 的依赖, | ||
| 18 | - 从而实现提供 RESTful API 给 yudao-ui-admin、yudao-ui-user 等前端项目。 | ||
| 19 | - 本质上来说,它就是个空壳(容器)! | ||
| 20 | - </description> | ||
| 21 | - | ||
| 22 | -</project> |
更新日志.md
| @@ -4,29 +4,30 @@ | @@ -4,29 +4,30 @@ | ||
| 4 | * 钉钉、飞书等通知 | 4 | * 钉钉、飞书等通知 |
| 5 | * Vue3 支持 | 5 | * Vue3 支持 |
| 6 | 6 | ||
| 7 | -## [v1.4.0] 计划 | ||
| 8 | - | ||
| 9 | -* 工作流 | ||
| 10 | - * 修改表单为外置表单 | ||
| 11 | - * 修改请假流程 | ||
| 12 | - * 暂时以用户的岗位作为activiti 的用户组 | ||
| 13 | - * 请假需要请假人部门下具有项目经理岗位, 部门经理, 和人事 岗位的用户 | ||
| 14 | - * 新增 芋道源码部门下 用户 normal(岗位 普通用户) projectmgr(岗位 项目经理) depmgr(岗位 部门经理) hradmin (岗位 人事) | ||
| 15 | - * 请假流程如下 | ||
| 16 | - 1. 请假人 normal (密码 123456) 登录在我的请假表单,点击新增,填写请假表单 | ||
| 17 | - 2. 如果请假天数<=3, 项目经理 进行审批. 项目经理 projectmgr(密码:123456) 登录 待办请假,中进行审批,可以查看历史跟踪,和流程图 | ||
| 18 | - 3. 如果请假天数>3 需部门经理 进行审批,部门经理depmgr(密码:123456) 登录 待办请假,中进行审批,可以查看历史跟踪,和流程图 | ||
| 19 | - 4. 人事登陆(用户名:hradmin 密码:123456) 登录 待办请假, 中进行审批,可以查看历史跟踪,和流程图 | ||
| 20 | - 5. 流程结束 | ||
| 21 | - * 我的请假中,可以查询本人的请假申请, 和进度 | ||
| 22 | - | ||
| 23 | ### 📝 TODO | 7 | ### 📝 TODO |
| 24 | 8 | ||
| 25 | * 支付 | 9 | * 支付 |
| 26 | * 用户前台的社交登陆 | 10 | * 用户前台的社交登陆 |
| 27 | * 用户前台的修改手机、修改密码、忘记密码 | 11 | * 用户前台的修改手机、修改密码、忘记密码 |
| 28 | 12 | ||
| 29 | -## [v1.3.0] 进行中 | 13 | +## [v1.4.0] 计划,预计 2022.02.28 发布 |
| 14 | + | ||
| 15 | +### ⚠️ Warning | ||
| 16 | + | ||
| 17 | +### 📈 Statistic | ||
| 18 | + | ||
| 19 | +### ⭐ New Features | ||
| 20 | + | ||
| 21 | +*【优化】操作日志新增用户类型,实现 APP 端的 API 的操作日志的记录 | ||
| 22 | + | ||
| 23 | +### 🐞 Bug Fixes | ||
| 24 | + | ||
| 25 | +*【修复】用户无权限访问 指定 API 时,未返回 FORBIDDEN 结果码 | ||
| 26 | + | ||
| 27 | +### 🔨 Dependency Upgrades | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +## [v1.3.0] 2022.01.24 | ||
| 30 | 31 | ||
| 31 | ### ⚠️ Warning | 32 | ### ⚠️ Warning |
| 32 | 33 |