Commit e9efff7076f66305b5bc80ee416a32ee7487b6dc

Authored by YunaiV
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 }
@@ -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
1 ### 请求 /login 接口 => 成功 1 ### 请求 /login 接口 => 成功
2 -POST {{userServerUrl}}/login 2 +POST {{userApi}}/login
3 Content-Type: application/json 3 Content-Type: application/json
  4 +tenant-id: {{userTenentId}}
4 5
5 { 6 {
6 "mobile": "15601691300", 7 "mobile": "15601691300",
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