diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java index 6f6e05a13..595450aec 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java @@ -20,6 +20,7 @@ import com.pig4cloud.pigx.auth.support.CustomeOAuth2AccessTokenGenerator; import com.pig4cloud.pigx.auth.support.core.CustomeOAuth2TokenCustomizer; import com.pig4cloud.pigx.auth.support.core.FormIdentityLoginConfigurer; import com.pig4cloud.pigx.auth.support.core.PigxDaoAuthenticationProvider; +import com.pig4cloud.pigx.auth.support.core.PigxOAuth2RefreshTokenAuthenticationConverter; import com.pig4cloud.pigx.auth.support.handler.PigxAuthenticationFailureEventHandler; import com.pig4cloud.pigx.auth.support.handler.PigxAuthenticationSuccessEventHandler; import com.pig4cloud.pigx.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationConverter; @@ -131,7 +132,7 @@ public class AuthorizationServerConfiguration { private AuthenticationConverter accessTokenRequestConverter() { return new DelegatingAuthenticationConverter(Arrays.asList( new OAuth2ResourceOwnerPasswordAuthenticationConverter(), - new OAuth2ResourceOwnerSmsAuthenticationConverter(), new OAuth2RefreshTokenAuthenticationConverter(), + new OAuth2ResourceOwnerSmsAuthenticationConverter(), new PigxOAuth2RefreshTokenAuthenticationConverter(), new OAuth2ClientCredentialsAuthenticationConverter(), new OAuth2AuthorizationCodeAuthenticationConverter(), new OAuth2AuthorizationCodeRequestAuthenticationConverter())); diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxOAuth2RefreshTokenAuthenticationConverter.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxOAuth2RefreshTokenAuthenticationConverter.java new file mode 100644 index 000000000..46ec90289 --- /dev/null +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxOAuth2RefreshTokenAuthenticationConverter.java @@ -0,0 +1,77 @@ +package com.pig4cloud.pigx.auth.support.core; + +import com.pig4cloud.pigx.common.security.util.OAuth2EndpointUtils; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.lang.Nullable; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationToken; +import org.springframework.security.web.authentication.AuthenticationConverter; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; + +import java.util.*; + +/** + * @author lengleng + * @date 2024/3/5 + * + * 覆盖原生的 OAuth2RefreshTokenAuthenticationConverter ,避免无法获取 query params + */ +public class PigxOAuth2RefreshTokenAuthenticationConverter implements AuthenticationConverter { + + @Nullable + @Override + public Authentication convert(HttpServletRequest request) { + MultiValueMap parameters = OAuth2EndpointUtils.getParameters(request); + + // grant_type (REQUIRED) + String grantType = parameters.getFirst(OAuth2ParameterNames.GRANT_TYPE); + if (!AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(grantType)) { + return null; + } + + Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication(); + + // refresh_token (REQUIRED) + String refreshToken = parameters.getFirst(OAuth2ParameterNames.REFRESH_TOKEN); + if (!StringUtils.hasText(refreshToken) || + parameters.get(OAuth2ParameterNames.REFRESH_TOKEN).size() != 1) { + OAuth2EndpointUtils.throwError( + OAuth2ErrorCodes.INVALID_REQUEST, + OAuth2ParameterNames.REFRESH_TOKEN, + OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); + } + + // scope (OPTIONAL) + String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE); + if (StringUtils.hasText(scope) && + parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) { + OAuth2EndpointUtils.throwError( + OAuth2ErrorCodes.INVALID_REQUEST, + OAuth2ParameterNames.SCOPE, + OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); + } + Set requestedScopes = null; + if (StringUtils.hasText(scope)) { + requestedScopes = new HashSet<>( + Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))); + } + + Map additionalParameters = new HashMap<>(); + parameters.forEach((key, value) -> { + if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) && + !key.equals(OAuth2ParameterNames.REFRESH_TOKEN) && + !key.equals(OAuth2ParameterNames.SCOPE)) { + additionalParameters.put(key, (value.size() == 1) ? value.get(0) : value.toArray(new String[0])); + } + }); + + return new OAuth2RefreshTokenAuthenticationToken( + refreshToken, clientPrincipal, requestedScopes, additionalParameters); + } +} +