Я также изменяю подход и создал пользовательскую CustomAuthenticationEntryPoint реализует аутентификацию IntryPoint и вставлен в фильтру, но ничего.
Это мои классы:
filterchain < /strong> < /p>
Код: Выделить всё
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@Profile("dev")
public class AuthServerConfigDev extends AuthServerConfigAbstract{
private static final Logger logger = LoggerFactory.getLogger(AuthServerConfigDev.class);
private final OAuth2AuthorizationService authorizationService;
private final TokenRevocationRepository tokenRevocationRepository;
public AuthServerConfigDev(@Lazy OAuth2AuthorizationService authorizationService, TokenRevocationRepository tokenRevocationRepository) {
this.authorizationService = authorizationService;
this.tokenRevocationRepository = tokenRevocationRepository;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authzServerConfigurer = new OAuth2AuthorizationServerConfigurer();
authzServerConfigurer
.oidc(withDefaults());
authzServerConfigurer
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint
.errorResponseHandler(new ClientAuthenticationFailureHandler()));
authzServerConfigurer
.tokenEndpoint(tokenEndpoint -> tokenEndpoint
.errorResponseHandler(new ClientAuthenticationFailureHandler()));
RequestMatcher endpointsMatcher = authzServerConfigurer.getEndpointsMatcher();
http.addFilterBefore(new GrantFlowFilter(new ClientAuthenticationFailureHandler()), UsernamePasswordAuthenticationFilter.class);
http
.securityMatchers(matchers -> matchers
.requestMatchers(
antMatcher(OPENAPI_JSON_URL),
antMatcher(SWAGGER_UI_URL),
antMatcher(REST_USER_PATH + "/**"),
antMatcher(REVOKE_ENDPOINT),
endpointsMatcher))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(HttpMethod.GET, OPENAPI_JSON_URL).hasAuthority("SCOPE.user")
.requestMatchers(HttpMethod.GET, SWAGGER_UI_URL).hasAuthority("SCOPE.user")
.requestMatchers(FULL_LOGIN_URL).permitAll()
.requestMatchers(REVOKE_ENDPOINT).authenticated()
.anyRequest().authenticated())
.csrf(csrf -> csrf
.ignoringRequestMatchers(endpointsMatcher))
.exceptionHandling(exceptions -> exceptions
.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint(FULL_LOGIN_URL + ParamMissingAuth),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)))
.oauth2ResourceServer(resourceServer -> resourceServer.jwt(withDefaults()))
.with(authzServerConfigurer, (authorizationServer) ->
authorizationServer
// As defined in the guide
.tokenRevocationEndpoint(tokenRevocationEndpoint ->
tokenRevocationEndpoint
.revocationRequestConverter(new CustomRevocationRequestConverter())
.authenticationProvider(new CustomRevocationAuthenticationProvider(authorizationService, tokenRevocationRepository))
.revocationResponseHandler(new CustomRevocationResponseHandler())
.errorResponseHandler(new CustomRevocationErrorResponseHandler())));
return http.build();
}
}
Код: Выделить всё
public class CustomRevocationRequestConverter implements AuthenticationConverter {
@Override
public Authentication convert(HttpServletRequest request) {
// Extract the token and token_type_hint from the request parameters
String tokenValue = request.getParameter("token");
String tokenTypeHint = request.getParameter("token_type_hint");
if (tokenValue == null || tokenValue.isEmpty()) {
return null; // Return null if the token is not present
}
// Retrieve the client authentication from the SecurityContext
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
// Create and return an OAuth2TokenRevocationAuthenticationToken
if(tokenTypeHint != null && !tokenTypeHint.isEmpty())
return new OAuth2TokenRevocationAuthenticationToken(tokenValue, clientPrincipal, tokenTypeHint);
else {
return new OAuth2TokenRevocationAuthenticationToken(tokenValue, clientPrincipal, null);
}
}
}
Код: Выделить всё
public class CustomRevocationAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(CustomRevocationAuthenticationProvider.class);
private final OAuth2AuthorizationService authorizationService;
private final TokenRevocationRepository tokenRevocationRepository;
public CustomRevocationAuthenticationProvider(OAuth2AuthorizationService authorizationService, TokenRevocationRepository tokenRevocationRepository) {
this.authorizationService = authorizationService;
this.tokenRevocationRepository = tokenRevocationRepository;
}
@Transactional
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// Check if the authentication object is an instance of OAuth2TokenRevocationAuthenticationToken
if (authentication instanceof OAuth2TokenRevocationAuthenticationToken revocationToken) {
// Extract the token and client authentication details
String tokenValue = revocationToken.getToken(); // JWT
Authentication clientPrincipal = (Authentication) revocationToken.getPrincipal(); // Cast the principal to Authentication
String tokenTypeHint = revocationToken.getTokenTypeHint(); // Token type [access_token, refresh_token]
String principalName = clientPrincipal.getName(); // Extract the principal name
try {
if (validateAndRevokeToken(tokenValue, tokenTypeHint, principalName)) {
return new OAuth2TokenRevocationAuthenticationToken(revocationToken.getToken(), clientPrincipal, "ROLE_REVOKER");
}
} catch (OAuth2AuthenticationException e) {
// Handle authentication exceptions gracefully
logger.error("{} - {}", "CustomRevocationAuthenticationProvider.authenticate", e.getError());
throw e;
// throw new AuthenticationServiceException(e.getError().getDescription(), e);
} catch (Exception e) {
// Catch all other exceptions including SQL exceptions
logger.error("{} - {}", "CustomRevocationAuthenticationProvider.authenticate", e);
throw new OAuth2AuthenticationException(new OAuth2Error(SERVER_ERROR, "An error occurred while processing the token revocation request", null), e);
}
}
// If the token is invalid or the authentication type is not supported, return null or throw an exception
throw new AuthenticationServiceException("Unsupported authentication token");
}
// Custom validation logic for the token
private boolean validateAndRevokeToken(String tokenValue, String tokenType, String principalName) {
try {
OAuth2Authorization authorization = authorizationService.findByToken(tokenValue, OAuth2TokenType.ACCESS_TOKEN);
if (authorization == null) {
return false; // Token does not exist
}
int deletedRows;
if(tokenType != null && tokenType.equalsIgnoreCase(OAuth2TokenType.ACCESS_TOKEN.getValue())) {
Optional oauth2ClientIdDTO = tokenRevocationRepository.findClientIdByAccessTokenValue(tokenValue);
validateClientIdDto(oauth2ClientIdDTO, principalName, authorization); // If a check fail it throws OAuth2AuthenticationException
deletedRows = tokenRevocationRepository.deleteByAccessTokenValue(tokenValue);
} else if (tokenType != null && tokenType.equalsIgnoreCase(OAuth2TokenType.REFRESH_TOKEN.getValue())) {
Optional oauth2ClientIdDTO = tokenRevocationRepository.findClientIdByRefreshTokenValue(tokenValue);
validateClientIdDto(oauth2ClientIdDTO, principalName, authorization); // If a check fail it throws OAuth2AuthenticationException
deletedRows = tokenRevocationRepository.deleteByRefreshTokenValue(tokenValue);
} else {
Optional oauth2ClientIdDTO = tokenRevocationRepository.findClientIdByAccessTokenValueOrRefreshToken(tokenValue, tokenValue);
validateClientIdDto(oauth2ClientIdDTO, principalName, authorization); // If a check fail it throws OAuth2AuthenticationException
deletedRows = tokenRevocationRepository.deleteByAccessTokenValueOrRefreshTokenValue(tokenValue, tokenValue);
}
if(deletedRows > 0)
logger.info("Token revoked.");
return true;
} catch (OAuth2AuthenticationException e) {
// Handle authentication exceptions gracefully
logger.error("{} - {}", "CustomRevocationAuthenticationProvider.validateAndRevokeToken", e.getError());
throw e;
} catch (Exception e) {
logger.error("{} - {}", "CustomRevocationAuthenticationProvider.validateAndRevokeToken", e);
throw new OAuth2AuthenticationException(new OAuth2Error(SERVER_ERROR, "An error occurred while validating the token", null), e);
}
}
private void validateClientIdDto(Optional oauth2ClientIdDTO, String principalName, OAuth2Authorization authorization) {
logger.debug("Validating client id of the token to revoke.");
oauth2ClientIdDTO.ifPresentOrElse(dto -> {
if (!dto.getClient_id().equalsIgnoreCase(principalName) || !dto.getId().equalsIgnoreCase(authorization.getRegisteredClientId())) {
throw new OAuth2AuthenticationException(new OAuth2Error(INVALID_CLIENT, "Client ID validation failed", null));
}}, () -> { // empty optional
throw new OAuth2AuthenticationException(new OAuth2Error(INVALID_CLIENT, "Client ID not found", null));
});
}
@Override
public boolean supports(Class authentication) {
return OAuth2TokenRevocationAuthenticationToken.class.isAssignableFrom(authentication);
}
}
Код: Выделить всё
public class CustomRevocationResponseHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
// Handle the success response for token revocation
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
response.getWriter().write("{\"message\":\"Token revoked successfully\"}");
}
}
Код: Выделить всё
public class CustomRevocationErrorResponseHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
if (exception instanceof OAuth2AuthenticationException) {
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
String errorCode = error.getErrorCode();
String errorDescription = error.getDescription();
// Set the appropriate HTTP status code and error response body based on RFC 6749 Section 5.2
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType("application/json");
String errorResponse = String.format("{\"error\":\"%s\",\"error_description\":\"%s\"}", errorCode, errorDescription);
response.getWriter().write(errorResponse);
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType("application/json");
response.getWriter().write("{\"error\":\"invalid_request\",\"error_description\":\"Invalid request\"}");
}
}
}
Код: Выделить всё
x s i : s c h e m a L o c a t i o n = & q u o t ; h t t p : / / m a v e n . a p a c h e . o r g / P O M / 4 . 0 . 0 h t t p s : / / m a v e n . a p a c h e . o r g / x s d / m a v e n - 4 . 0 . 0 . x s d & q u o t ; & g t ; < b r / > & l t ; m o d e l V e r s i o n & g t ; 4 . 0 . 0 & l t ; / m o d e l V e r s i o n & g t ; < b r / > < b r / > & l t ; p a c k a g i n g & g t ; j a r & l t ; / p a c k a g i n g & g t ; < b r / > < b r / > & l t ; p r o p e r t i e s & g t ; < b r / > & l t ; j a v a . v e r s i o n & g t ; 1 7 & l t ; / j a v a . v e r s i o n & g t ; < b r / > & l t ; m a v e n . c o m p i l e r . t a r g e t & g t ; 1 7 & l t ; / m a v e n . c o m p i l e r . t a r g e t & g t ; < b r / > & l t ; m a v e n . c o m p i l e r . s o u r c e & g t ; 1 7 & l t ; / m a v e n . c o m p i l e r . s o u r c e & g t ; < b r / > & l t ; p r o j e c t . b u i l d . s o u r c e E n c o d i n g & g t ; U T F - 8 & l t ; / p r o j e c t . b u i l d . s o u r c e E n c o d i n g & g t ; < b r / > & l t ; p r o j e c t . r e p o r t i n g . o u t p u t E n c o d i n g & g t ; U T F 8 & l t ; / p r o j e c t . r e p o r t i n g . o u t p u t E n c o d i n g & g t ; < b r / > & l t ; s p r i n g b o o t . v e r s i o n & g t ; 3 . 4 . 2 & l t ; / s p r i n g b o o t . v e r s i o n & g t ; < b r / > & l t ; s p r i n g s e c u r i t y . v e r s i o n & g t ; 6 . 4 . 2 & l t ; / s p r i n g s e c u r i t y . v e r s i o n & g t ; < b r / > & l t ; a u t h . s e r v e r . v e r s i o n & g t ; 1 . 4 . 1 & l t ; / a u t h . s e r v e r . v e r s i o n & g t ; < b r / > & l t ; s p r i n g . o a u t h 2 . c l i e n t . v e r s i o n & g t ; 6 . 4 . 2 & l t ; / s p r i n g . o a u t h 2 . c l i e n t . v e r s i o n & g t ; < b r / > & l t ; s p r i n g . b o o t . s t a r t e r . l o g 4 j 2 . v e r s i o n & g t ; 3 . 4 . 2 & l t ; / s p r i n g . b o o t . s t a r t e r . l o g 4 j 2 . v e r s i o n & g t ; < b r / > & l t ; s q l . s e r v e r . j d b c . v e r s i o n & g t ; 1 2 . 8 . 1 . j r e 8 & l t ; / s q l . s e r v e r . j d b c . v e r s i o n & g t ; < b r / > & l t ; o p e n . a p i . v e r sion>2.8.3
3.17.0
3.4.1
1.17.0
2.0.1
org.springframework.security
spring-security-config
${springsecurity.version}
org.springframework.security
spring-security-oauth2-authorization-server
${auth.server.version}
org.springframework.security
spring-security-oauth2-client
${spring.oauth2.client.version}
org.springframework.boot
spring-boot-starter-web
${springboot.version}
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-data-jpa
${springboot.version}
com.microsoft.sqlserver
mssql-jdbc
runtime
${sql.server.jdbc.version}
org.springframework.boot
spring-boot-starter-log4j2
${spring.boot.starter.log4j2.version}
org.springframework.boot
spring-boot-starter-mail
${springboot.version}
org.apache.commons
commons-lang3
${apache.common.lang.version}
org.springframework.session
spring-session-jdbc
${spring.session.jdbc.version}
org.springframework.boot
spring-boot-starter-thymeleaf
${springboot.version}
org.springdoc
springdoc-openapi-starter-webmvc-ui
${open.api.version}
net.bytebuddy
byte-buddy
${byte.buddy.version}
com.sun.mail
jakarta.mail
${jakarta.mail.version}
org.springframework.boot
spring-boot-starter-test
${springboot.version}
test
org.springframework.security
spring-security-test
${springsecurity.version}
test
org.springframework.boot
spring-boot-maven-plugin
${springboot.version}
repackage
build-info
build-info
Если исключение происходит внутри CustomRevocationRequestConverter < /em> все в порядке. < /P>
может кто -то кто -то Скажите, если я что -то не так?>
Подробнее здесь: https://stackoverflow.com/questions/794 ... n-endpoint