diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfig.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java similarity index 78% rename from pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfig.java rename to pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java index 20ea69b9d..e675d14fd 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfig.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java @@ -22,6 +22,7 @@ package com.pig4cloud.pigx.auth.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.pig4cloud.pigx.common.security.component.PigxCommenceAuthExceptionEntryPoint; import com.pig4cloud.pigx.common.security.component.PigxWebResponseExceptionTranslator; +import com.pig4cloud.pigx.common.security.grant.ResourceOwnerCustomeAppTokenGranter; import com.pig4cloud.pigx.common.security.service.PigxCustomTokenServices; import lombok.AllArgsConstructor; import lombok.SneakyThrows; @@ -38,11 +39,15 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.E import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.CompositeTokenGranter; +import org.springframework.security.oauth2.provider.TokenGranter; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; /** @@ -52,7 +57,7 @@ import java.util.Collections; @Configuration @AllArgsConstructor @EnableAuthorizationServer -public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { +public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { private final ClientDetailsService pigxClientDetailsServiceImpl; @@ -62,6 +67,8 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap private final AuthorizationCodeServices authorizationCodeServices; + private final AuthenticationManager authenticationManager; + private final TokenStore redisTokenStore; private final TokenEnhancer tokenEnhancer; @@ -84,10 +91,29 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenServices(tokenServices()) - .tokenStore(redisTokenStore).tokenEnhancer(tokenEnhancer).userDetailsService(pigxUserDetailsService) + .tokenStore(redisTokenStore).tokenEnhancer(tokenEnhancer) .authorizationCodeServices(authorizationCodeServices).authenticationManager(authenticationManagerBean) .reuseRefreshTokens(false).pathMapping("/oauth/confirm_access", "/token/confirm_access") .exceptionTranslator(new PigxWebResponseExceptionTranslator()); + + // 注入自定义认证类型 + setTokenGranter(endpoints); + } + + /** + * 自定义 APP 认证类型 + * @param endpoints AuthorizationServerEndpointsConfigurer + */ + private void setTokenGranter(AuthorizationServerEndpointsConfigurer endpoints) { + // 获取默认授权类型 + TokenGranter tokenGranter = endpoints.getTokenGranter(); + ArrayList tokenGranters = new ArrayList<>(Arrays.asList(tokenGranter)); + ResourceOwnerCustomeAppTokenGranter resourceOwnerCustomeAppTokenGranter = new ResourceOwnerCustomeAppTokenGranter( + authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), + endpoints.getOAuth2RequestFactory()); + tokenGranters.add(resourceOwnerCustomeAppTokenGranter); + CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters); + endpoints.tokenGranter(compositeTokenGranter); } @Bean diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java index d2ce2618f..38f9dffe3 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java @@ -91,19 +91,9 @@ public interface SecurityConstants { String OAUTH_TOKEN_URL = "/oauth/token"; /** - * 手机号登录URL + * 移动端授权 */ - String SMS_TOKEN_URL = "/mobile/token/sms"; - - /** - * 社交登录URL - */ - String SOCIAL_TOKEN_URL = "/mobile/token/social"; - - /** - * 自定义登录URL - */ - String MOBILE_TOKEN_URL = "/mobile/token/*"; + String GRANT_MOBILE = "mobile"; /** * 微信获取OPENID diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxDaoAuthenticationProvider.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxDaoAuthenticationProvider.java new file mode 100644 index 000000000..c8a07975a --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxDaoAuthenticationProvider.java @@ -0,0 +1,174 @@ +package com.pig4cloud.pigx.common.security.component; + +import cn.hutool.extra.spring.SpringUtil; +import com.pig4cloud.pigx.common.core.util.WebUtils; +import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService; +import org.springframework.core.Ordered; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsPasswordService; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.Assert; + +import java.util.Comparator; +import java.util.Map; +import java.util.Optional; + +/** + * @author lengleng + * @date 2022/1/15 + */ +public class PigxDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { + + /** + * The plaintext password used to perform PasswordEncoder#matches(CharSequence, + * String)} on when the user is not found to avoid SEC-2056. + */ + private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword"; + + private PasswordEncoder passwordEncoder; + + /** + * The password used to perform {@link PasswordEncoder#matches(CharSequence, String)} + * on when the user is not found to avoid SEC-2056. This is necessary, because some + * {@link PasswordEncoder} implementations will short circuit if the password is not + * in a valid format. + */ + private volatile String userNotFoundEncodedPassword; + + private UserDetailsService userDetailsService; + + private UserDetailsPasswordService userDetailsPasswordService; + + public PigxDaoAuthenticationProvider() { + setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()); + } + + @Override + @SuppressWarnings("deprecation") + protected void additionalAuthenticationChecks(UserDetails userDetails, + UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + if (authentication.getCredentials() == null) { + this.logger.debug("Failed to authenticate since no credentials provided"); + throw new BadCredentialsException(this.messages + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + String presentedPassword = authentication.getCredentials().toString(); + if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { + this.logger.debug("Failed to authenticate since password does not match stored value"); + throw new BadCredentialsException(this.messages + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + } + + @Override + protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) + throws AuthenticationException { + prepareTimingAttackProtection(); + + // 此处已获得 客户端认证 获取对应 userDetailsService + Authentication clientAuthentication = SecurityContextHolder.getContext().getAuthentication(); + + // SSO NPE 处理 + String clientId; + if (clientAuthentication == null) { + clientId = WebUtils.getRequest().getParameter("clientId"); + } + else { + clientId = clientAuthentication.getName(); + } + + Map userDetailsServiceMap = SpringUtil + .getBeansOfType(PigxUserDetailsService.class); + Optional optional = userDetailsServiceMap.values().stream() + .filter(service -> service.support(clientId, null)).max(Comparator.comparingInt(Ordered::getOrder)); + + if (!optional.isPresent()) { + throw new InternalAuthenticationServiceException("UserDetailsService error , not register"); + } + + try { + UserDetails loadedUser = optional.get().loadUserByUsername(username); + if (loadedUser == null) { + throw new InternalAuthenticationServiceException( + "UserDetailsService returned null, which is an interface contract violation"); + } + return loadedUser; + } + catch (UsernameNotFoundException ex) { + mitigateAgainstTimingAttack(authentication); + throw ex; + } + catch (InternalAuthenticationServiceException ex) { + throw ex; + } + catch (Exception ex) { + throw new InternalAuthenticationServiceException(ex.getMessage(), ex); + } + } + + @Override + protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, + UserDetails user) { + boolean upgradeEncoding = this.userDetailsPasswordService != null + && this.passwordEncoder.upgradeEncoding(user.getPassword()); + if (upgradeEncoding) { + String presentedPassword = authentication.getCredentials().toString(); + String newPassword = this.passwordEncoder.encode(presentedPassword); + user = this.userDetailsPasswordService.updatePassword(user, newPassword); + } + return super.createSuccessAuthentication(principal, authentication, user); + } + + private void prepareTimingAttackProtection() { + if (this.userNotFoundEncodedPassword == null) { + this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD); + } + } + + private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) { + if (authentication.getCredentials() != null) { + String presentedPassword = authentication.getCredentials().toString(); + this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword); + } + } + + /** + * Sets the PasswordEncoder instance to be used to encode and validate passwords. If + * not set, the password will be compared using + * {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()} + * @param passwordEncoder must be an instance of one of the {@code PasswordEncoder} + * types. + */ + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + Assert.notNull(passwordEncoder, "passwordEncoder cannot be null"); + this.passwordEncoder = passwordEncoder; + this.userNotFoundEncodedPassword = null; + } + + protected PasswordEncoder getPasswordEncoder() { + return this.passwordEncoder; + } + + public void setUserDetailsService(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + + protected UserDetailsService getUserDetailsService() { + return this.userDetailsService; + } + + public void setUserDetailsPasswordService(UserDetailsPasswordService userDetailsPasswordService) { + this.userDetailsPasswordService = userDetailsPasswordService; + } + +} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxLocalResourceServerTokenServices.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxLocalResourceServerTokenServices.java index b48ddd518..1bd60640f 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxLocalResourceServerTokenServices.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxLocalResourceServerTokenServices.java @@ -1,14 +1,17 @@ package com.pig4cloud.pigx.common.security.component; +import cn.hutool.extra.spring.SpringUtil; import com.pig4cloud.pigx.common.security.exception.UnauthorizedException; import com.pig4cloud.pigx.common.security.service.PigxUser; +import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Primary; +import org.springframework.core.Ordered; +import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; @@ -18,6 +21,10 @@ import org.springframework.security.oauth2.provider.token.ResourceServerTokenSer import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.stereotype.Service; +import java.util.Comparator; +import java.util.Map; +import java.util.Optional; + /** * @author lengleng * @date 2020/9/29 @@ -29,8 +36,6 @@ public class PigxLocalResourceServerTokenServices implements ResourceServerToken private final TokenStore tokenStore; - private final UserDetailsService userDetailsService; - @Override public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { @@ -44,15 +49,28 @@ public class PigxLocalResourceServerTokenServices implements ResourceServerToken return oAuth2Authentication; } + String clientId = oAuth2Request.getClientId(); + + Map userDetailsServiceMap = SpringUtil + .getBeansOfType(PigxUserDetailsService.class); + + Optional optional = userDetailsServiceMap.values().stream() + .filter(service -> service.support(clientId, oAuth2Request.getGrantType())) + .max(Comparator.comparingInt(Ordered::getOrder)); + + if (!optional.isPresent()) { + throw new InternalAuthenticationServiceException("UserDetailsService error , not register"); + } + // 根据 username 查询 spring cache 最新的值 并返回 - PigxUser pigxUser = (PigxUser) oAuth2Authentication.getPrincipal(); + PigxUser pigUser = (PigxUser) oAuth2Authentication.getPrincipal(); UserDetails userDetails; try { - userDetails = userDetailsService.loadUserByUsername(pigxUser.getUsername()); + userDetails = optional.get().loadUserByUser(pigUser); } catch (UsernameNotFoundException notFoundException) { - throw new UnauthorizedException(String.format("%s username not found", pigxUser.getUsername()), + throw new UnauthorizedException(String.format("%s username not found", pigUser.getUsername()), notFoundException); } Authentication userAuthentication = new UsernamePasswordAuthenticationToken(userDetails, "N/A", diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/CustomAppAuthenticationProvider.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/CustomAppAuthenticationProvider.java new file mode 100644 index 000000000..fb805de0c --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/CustomAppAuthenticationProvider.java @@ -0,0 +1,100 @@ +package com.pig4cloud.pigx.common.security.grant; + +import cn.hutool.extra.spring.SpringUtil; +import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.Ordered; +import org.springframework.security.authentication.AccountStatusUserDetailsChecker; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsChecker; + +import java.util.Comparator; +import java.util.Map; +import java.util.Optional; + +/** + * @author hzq + * @since 2021-09-14 + */ +@Slf4j +public class CustomAppAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { + + /** + * user 属性校验 + */ + @Setter + private UserDetailsChecker preAuthenticationChecks = new AccountStatusUserDetailsChecker(); + + /** + * 校验 请求信息userDetails + * @param userDetails 用户信息 + * @param authentication 认证信息 + * @throws AuthenticationException + */ + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, + UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + + if (authentication.getCredentials() == null) { + this.logger.debug("Failed to authenticate since no credentials provided"); + throw new BadCredentialsException(this.messages + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + + if (authentication.getCredentials() == null) { + log.debug("Failed to authenticate since no credentials provided"); + throw new BadCredentialsException("Bad credentials"); + } + + CustomAppAuthenticationToken requestToken = (CustomAppAuthenticationToken) authentication; + // 此处已获得 客户端认证 获取对应 userDetailsService + Authentication clientAuthentication = SecurityContextHolder.getContext().getAuthentication(); + String clientId = clientAuthentication.getName(); + + Map userDetailsServiceMap = SpringUtil + .getBeansOfType(PigxUserDetailsService.class); + Optional optional = userDetailsServiceMap.values().stream() + .filter(service -> service.support(clientId, requestToken.getGrantType())) + .max(Comparator.comparingInt(Ordered::getOrder)); + + if (!optional.isPresent()) { + throw new InternalAuthenticationServiceException("UserDetailsService error , not register"); + } + + // 手机号 + String phone = authentication.getName(); + UserDetails userDetails = optional.get().loadUserByUsername(phone); + + // userDeails 校验 + preAuthenticationChecks.check(userDetails); + + CustomAppAuthenticationToken token = new CustomAppAuthenticationToken(userDetails); + token.setDetails(authentication.getDetails()); + return token; + } + + @Override + protected UserDetails retrieveUser(String phone, UsernamePasswordAuthenticationToken authentication) + throws AuthenticationException { + return null; + } + + @Override + public boolean supports(Class authentication) { + return authentication.isAssignableFrom(CustomAppAuthenticationToken.class); + } + +} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/CustomAppAuthenticationToken.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/CustomAppAuthenticationToken.java new file mode 100644 index 000000000..365110ae7 --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/CustomAppAuthenticationToken.java @@ -0,0 +1,50 @@ +package com.pig4cloud.pigx.common.security.grant; + +import lombok.Getter; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * @author hzq + * @since 2021-09-14 + */ +public class CustomAppAuthenticationToken extends AbstractAuthenticationToken { + + private final Object principal; + + /** + * 验证码/密码 + */ + private String code; + + /** + * 授权类型 + */ + @Getter + private String grantType; + + public CustomAppAuthenticationToken(String phone, String code, String grantType) { + super(AuthorityUtils.NO_AUTHORITIES); + this.principal = phone; + this.code = code; + this.grantType = grantType; + } + + public CustomAppAuthenticationToken(UserDetails sysUser) { + super(sysUser.getAuthorities()); + this.principal = sysUser; + super.setAuthenticated(true); // 设置认证成功 必须 + } + + @Override + public Object getPrincipal() { + return this.principal; + } + + @Override + public Object getCredentials() { + return this.code; + } + +} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/ResourceOwnerCustomeAppTokenGranter.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/ResourceOwnerCustomeAppTokenGranter.java new file mode 100644 index 000000000..c6d96167b --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/grant/ResourceOwnerCustomeAppTokenGranter.java @@ -0,0 +1,78 @@ +package com.pig4cloud.pigx.common.security.grant; + +import cn.hutool.core.util.StrUtil; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AccountStatusException; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.provider.*; +import org.springframework.security.oauth2.provider.token.AbstractTokenGranter; +import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 资源所有者电话令牌授予者 + * + * @author hzq + * @since 2021-09-14 + */ +public class ResourceOwnerCustomeAppTokenGranter extends AbstractTokenGranter { + + private static final String GRANT_TYPE = "mobile"; + + private final AuthenticationManager authenticationManager; + + public ResourceOwnerCustomeAppTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory) { + this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); + } + + protected ResourceOwnerCustomeAppTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory, String grantType) { + super(tokenServices, clientDetailsService, requestFactory, grantType); + this.authenticationManager = authenticationManager; + } + + @Override + protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { + + Map parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters()); + + // 手机号 + String mobile = parameters.get("mobile"); + // 验证码/密码 + String code = parameters.get("code"); + + if (StrUtil.isBlank(mobile) || StrUtil.isBlank(code)) { + throw new InvalidGrantException("Bad credentials [ params must be has phone with code ]"); + } + + // Protect from downstream leaks of code + parameters.remove("code"); + + Authentication userAuth = new CustomAppAuthenticationToken(mobile, code, tokenRequest.getGrantType()); + ((AbstractAuthenticationToken) userAuth).setDetails(parameters); + try { + userAuth = authenticationManager.authenticate(userAuth); + } + catch (AccountStatusException | BadCredentialsException ase) { + // covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) + throw new InvalidGrantException(ase.getMessage()); + } + // If the phone/code are wrong the spec says we should send 400/invalid grant + + if (userAuth == null || !userAuth.isAuthenticated()) { + throw new InvalidGrantException("Could not authenticate user: " + mobile); + } + + OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); + return new OAuth2Authentication(storedOAuth2Request, userAuth); + } + +} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationFilter.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationFilter.java deleted file mode 100644 index a351aea2f..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationFilter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.common.security.mobile; - -import com.pig4cloud.pigx.common.core.constant.SecurityConstants; -import lombok.Getter; -import lombok.Setter; -import lombok.SneakyThrows; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * @author lengleng - * @date 2018/1/9 手机号登录验证filter - */ -public class MobileAuthenticationFilter extends AbstractAuthenticationProcessingFilter { - - private static final String SPRING_SECURITY_FORM_MOBILE_KEY = "mobile"; - - @Getter - @Setter - private String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY; - - @Getter - @Setter - private boolean postOnly = true; - - @Getter - @Setter - private AuthenticationEntryPoint authenticationEntryPoint; - - public MobileAuthenticationFilter() { - super(new AntPathRequestMatcher(SecurityConstants.MOBILE_TOKEN_URL, "POST")); - } - - @Override - @SneakyThrows - public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) { - if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { - throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); - } - - String mobile = obtainMobile(request); - - if (mobile == null) { - mobile = ""; - } - - mobile = mobile.trim(); - - MobileAuthenticationToken mobileAuthenticationToken = new MobileAuthenticationToken(mobile); - - setDetails(request, mobileAuthenticationToken); - - Authentication authResult = null; - try { - authResult = this.getAuthenticationManager().authenticate(mobileAuthenticationToken); - - logger.debug("Authentication success: " + authResult); - SecurityContextHolder.getContext().setAuthentication(authResult); - - } - catch (Exception failed) { - SecurityContextHolder.clearContext(); - logger.debug("Authentication request failed: " + failed); - - try { - authenticationEntryPoint.commence(request, response, - new UsernameNotFoundException(failed.getMessage(), failed)); - } - catch (Exception e) { - logger.error("authenticationEntryPoint handle error:{}", failed); - } - } - - return authResult; - } - - private String obtainMobile(HttpServletRequest request) { - return request.getParameter(mobileParameter); - } - - private void setDetails(HttpServletRequest request, MobileAuthenticationToken authRequest) { - authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); - } - -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationProvider.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationProvider.java deleted file mode 100644 index a10f7fa97..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationProvider.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.common.security.mobile; - -import com.pig4cloud.pigx.common.security.component.PigxPreAuthenticationChecks; -import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService; -import com.pig4cloud.pigx.common.security.util.PigxSecurityMessageSourceUtil; -import lombok.Getter; -import lombok.Setter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.support.MessageSourceAccessor; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsChecker; - -/** - * @author lengleng - * @date 2018/8/5 手机登录校验逻辑 验证码登录、社交登录 - */ -@Slf4j -public class MobileAuthenticationProvider implements AuthenticationProvider { - - private MessageSourceAccessor messages = PigxSecurityMessageSourceUtil.getAccessor(); - - private UserDetailsChecker detailsChecker = new PigxPreAuthenticationChecks(); - - @Getter - @Setter - private PigxUserDetailsService userDetailsService; - - @Override - @SneakyThrows - public Authentication authenticate(Authentication authentication) { - MobileAuthenticationToken mobileAuthenticationToken = (MobileAuthenticationToken) authentication; - - String principal = mobileAuthenticationToken.getPrincipal().toString(); - UserDetails userDetails = userDetailsService.loadUserBySocial(principal); - if (userDetails == null) { - log.debug("Authentication failed: no credentials provided"); - - throw new BadCredentialsException(messages - .getMessage("AbstractUserDetailsAuthenticationProvider.noopBindAccount", "Noop Bind Account")); - } - - // 检查账号状态 - detailsChecker.check(userDetails); - - MobileAuthenticationToken authenticationToken = new MobileAuthenticationToken(userDetails, - userDetails.getAuthorities()); - authenticationToken.setDetails(mobileAuthenticationToken.getDetails()); - return authenticationToken; - } - - @Override - public boolean supports(Class authentication) { - return MobileAuthenticationToken.class.isAssignableFrom(authentication); - } - -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationToken.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationToken.java deleted file mode 100644 index bb10ffc91..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationToken.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.common.security.mobile; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.SneakyThrows; -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.SpringSecurityCoreVersion; - -import java.util.Collection; - -/** - * @author lengleng - * @date 2018/1/9 手机号登录令牌 - */ -public class MobileAuthenticationToken extends AbstractAuthenticationToken { - - private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; - - private final Object principal; - - public MobileAuthenticationToken(String mobile) { - super(null); - this.principal = mobile; - setAuthenticated(false); - } - - @JsonCreator - public MobileAuthenticationToken(@JsonProperty("principal") Object principal, - @JsonProperty("authorities") Collection authorities) { - super(authorities); - this.principal = principal; - super.setAuthenticated(true); - } - - @Override - public Object getPrincipal() { - return this.principal; - } - - @Override - public Object getCredentials() { - return null; - } - - @Override - @SneakyThrows - public void setAuthenticated(boolean isAuthenticated) { - if (isAuthenticated) { - throw new IllegalArgumentException( - "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); - } - - super.setAuthenticated(false); - } - - @Override - public void eraseCredentials() { - super.eraseCredentials(); - } - -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileSecurityConfigurer.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileSecurityConfigurer.java deleted file mode 100644 index 7bc70ae1d..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileSecurityConfigurer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.common.security.mobile; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.pig4cloud.pigx.common.security.component.PigxCommenceAuthExceptionEntryPoint; -import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService; -import lombok.Getter; -import lombok.Setter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.SecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -/** - * @author lengleng - * @date 2018/8/5 手机号登录配置入口 - */ -@Getter -@Setter -public class MobileSecurityConfigurer extends SecurityConfigurerAdapter { - - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private AuthenticationSuccessHandler mobileLoginSuccessHandler; - - @Autowired - private PigxUserDetailsService userDetailsService; - - @Override - public void configure(HttpSecurity http) { - MobileAuthenticationFilter mobileAuthenticationFilter = new MobileAuthenticationFilter(); - mobileAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); - mobileAuthenticationFilter.setAuthenticationSuccessHandler(mobileLoginSuccessHandler); - mobileAuthenticationFilter.setAuthenticationEntryPoint(new PigxCommenceAuthExceptionEntryPoint(objectMapper)); - - MobileAuthenticationProvider mobileAuthenticationProvider = new MobileAuthenticationProvider(); - mobileAuthenticationProvider.setUserDetailsService(userDetailsService); - http.authenticationProvider(mobileAuthenticationProvider).addFilterAfter(mobileAuthenticationFilter, - UsernamePasswordAuthenticationFilter.class); - } - -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxAppUserDetailsServiceImpl.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxAppUserDetailsServiceImpl.java new file mode 100755 index 000000000..bfac04a19 --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxAppUserDetailsServiceImpl.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pig4cloud.pigx.common.security.service; + +import com.pig4cloud.pigx.admin.api.dto.UserInfo; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.constant.CacheConstants; +import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.common.core.util.R; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; + +/** + * 用户详细信息 + * + * @author lengleng hccake + */ +@Slf4j +@RequiredArgsConstructor +public class PigxAppUserDetailsServiceImpl implements PigxUserDetailsService { + + private final UserDetailsService pigxDefaultUserDetailsServiceImpl; + + private final RemoteUserService remoteUserService; + + private final CacheManager cacheManager; + + /** + * 手机号登录 + * @param phone 手机号 + * @return + */ + @Override + @SneakyThrows + public UserDetails loadUserByUsername(String phone) { + Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS); + if (cache != null && cache.get(phone) != null) { + return (PigxUser) cache.get(phone).get(); + } + + R result = remoteUserService.social(phone, SecurityConstants.FROM_IN); + + UserDetails userDetails = getUserDetails(result); + if (cache != null) { + cache.put(phone, userDetails); + } + return userDetails; + } + + /** + * check-token 使用 + * @param pigxUser user + * @return UserDetails + */ + @Override + public UserDetails loadUserByUser(PigxUser pigxUser) { + return pigxDefaultUserDetailsServiceImpl.loadUserByUsername(pigxUser.getUsername()); + } + + /** + * 支持所有的 mobile 类型 + * @param clientId 目标客户端 + * @param grantType 授权类型 + * @return true/false + */ + @Override + public boolean support(String clientId, String grantType) { + return SecurityConstants.GRANT_MOBILE.equals(grantType); + } + +} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsServiceImpl.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java similarity index 53% rename from pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsServiceImpl.java rename to pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java index 72ecd56af..25506a0da 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsServiceImpl.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxDefaultUserDetailsServiceImpl.java @@ -17,13 +17,9 @@ package com.pig4cloud.pigx.common.security.service; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; import com.pig4cloud.pigx.admin.api.dto.UserInfo; -import com.pig4cloud.pigx.admin.api.entity.SysUser; import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; import com.pig4cloud.pigx.common.core.constant.CacheConstants; -import com.pig4cloud.pigx.common.core.constant.CommonConstants; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.util.R; import lombok.RequiredArgsConstructor; @@ -32,25 +28,18 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Primary; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - /** - * 用户详细信息 + * 用户详细信息 default * * @author lengleng */ @Slf4j @Primary @RequiredArgsConstructor -public class PigxUserDetailsServiceImpl implements PigxUserDetailsService { +public class PigxDefaultUserDetailsServiceImpl implements PigxUserDetailsService { private final RemoteUserService remoteUserService; @@ -76,47 +65,9 @@ public class PigxUserDetailsServiceImpl implements PigxUserDetailsService { return userDetails; } - /** - * 根据社交登录code 登录 - * @param inStr TYPE@CODE - * @return UserDetails - * @throws UsernameNotFoundException - */ @Override - @SneakyThrows - public UserDetails loadUserBySocial(String inStr) { - return getUserDetails(remoteUserService.social(inStr, SecurityConstants.FROM_IN)); - } - - /** - * 构建userdetails - * @param result 用户信息 - * @return - */ - private UserDetails getUserDetails(R result) { - if (result == null || result.getData() == null) { - throw new UsernameNotFoundException("用户不存在"); - } - - UserInfo info = result.getData(); - Set dbAuthsSet = new HashSet<>(); - if (ArrayUtil.isNotEmpty(info.getRoles())) { - // 获取角色 - Arrays.stream(info.getRoles()).forEach(roleId -> dbAuthsSet.add(SecurityConstants.ROLE + roleId)); - // 获取资源 - dbAuthsSet.addAll(Arrays.asList(info.getPermissions())); - - } - Collection authorities = AuthorityUtils - .createAuthorityList(dbAuthsSet.toArray(new String[0])); - SysUser user = info.getSysUser(); - boolean enabled = StrUtil.equals(user.getLockFlag(), CommonConstants.STATUS_NORMAL); - // 构造security用户 - - return new PigxUser(user.getUserId(), user.getUsername(), user.getDeptId(), user.getPhone(), user.getAvatar(), - user.getNickname(), user.getName(), user.getEmail(), user.getTenantId(), - SecurityConstants.BCRYPT + user.getPassword(), enabled, true, true, - !CommonConstants.STATUS_LOCK.equals(user.getLockFlag()), authorities); + public int getOrder() { + return Integer.MIN_VALUE; } } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java index 0fc4cbdb5..ee78b9e5e 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java @@ -16,22 +16,85 @@ */ package com.pig4cloud.pigx.common.security.service; +import cn.hutool.core.util.ArrayUtil; +import com.pig4cloud.pigx.admin.api.dto.UserInfo; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.common.core.util.R; +import org.springframework.core.Ordered; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + /** * @author lengleng * @date 2018/8/15 */ -public interface PigxUserDetailsService extends UserDetailsService { +public interface PigxUserDetailsService extends UserDetailsService, Ordered { /** - * 根据社交登录code 登录 - * @param code TYPE@CODE - * @return UserDetails - * @throws UsernameNotFoundException + * 是否支持此客户端校验 + * @param clientId 请求客户端 + * @param grantType 授权类型 + * @return true/false */ - UserDetails loadUserBySocial(String code) throws UsernameNotFoundException; + default boolean support(String clientId, String grantType) { + return true; + } + + /** + * 排序值 默认取最大的 + * @return 排序值 + */ + default int getOrder() { + return 0; + } + + /** + * 构建userdetails + * @param result 用户信息 + * @return UserDetails + */ + default UserDetails getUserDetails(R result) { + if (result == null || result.getData() == null) { + throw new UsernameNotFoundException("用户不存在"); + } + + UserInfo info = result.getData(); + Set dbAuthsSet = new HashSet<>(); + if (ArrayUtil.isNotEmpty(info.getRoles())) { + // 获取角色 + Arrays.stream(info.getRoles()).forEach(roleId -> dbAuthsSet.add(SecurityConstants.ROLE + roleId)); + // 获取资源 + dbAuthsSet.addAll(Arrays.asList(info.getPermissions())); + + } + Collection authorities = AuthorityUtils + .createAuthorityList(dbAuthsSet.toArray(new String[0])); + SysUser user = info.getSysUser(); + // 构造security用户 + + return new PigxUser(user.getUserId(), user.getUsername(), user.getDeptId(), user.getPhone(), user.getAvatar(), + user.getNickname(), user.getName(), user.getEmail(), user.getTenantId(), + SecurityConstants.BCRYPT + user.getPassword(), true, true, true, + !CommonConstants.STATUS_LOCK.equals(user.getLockFlag()), authorities); + } + + /** + * 通过用户实体查询 + * @param pigxUser user + * @return + */ + default UserDetails loadUserByUser(PigxUser pigxUser) { + return this.loadUserByUsername(pigxUser.getUsername()); + } } diff --git a/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories b/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories index 0c4475a72..4bc46e709 100644 --- a/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories +++ b/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories @@ -1,7 +1,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.pig4cloud.pigx.common.security.component.PigxTokenEnhancer,\ com.pig4cloud.pigx.common.security.component.PigxSecurityInnerAspect,\ - com.pig4cloud.pigx.common.security.service.PigxUserDetailsServiceImpl,\ + com.pig4cloud.pigx.common.security.service.PigxDefaultUserDetailsServiceImpl,\ + com.pig4cloud.pigx.common.security.service.PigxAppUserDetailsServiceImpl,\ com.pig4cloud.pigx.common.security.service.PigxClientDetailsServiceImpl,\ com.pig4cloud.pigx.common.security.component.PigxTokenStoreAutoConfiguration,\ com.pig4cloud.pigx.common.security.component.PigxSecurityMessageSourceConfiguration,\ diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java index e79593dad..711662a30 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java @@ -67,8 +67,7 @@ public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory { ServerHttpRequest request = exchange.getRequest(); // 不是账号密码登录、短信登录,直接向下执行 - if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL, - SecurityConstants.SMS_TOKEN_URL)) { + if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) { return chain.filter(exchange); }