ResourceServerSecurityConfiguration.java
package com.project.auth.config.auth;
import com.project.auth.config.auth.security.KeycloakAuthenticatedUserFactory;
import com.project.auth.config.auth.security.KeycloakGrantedAuthoritiesConverter;
import com.project.auth.config.auth.security.KeycloakJwtAuthenticationConverter;
import com.project.auth.config.auth.security.SecurityActorIdResolver;
import com.project.auth.config.auth.security.SecurityAuditTrailWriter;
import com.project.auth.config.auth.security.SecurityExceptionHandler;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.servlet.HandlerExceptionResolver;
import java.util.Collection;
@Configuration
public class ResourceServerSecurityConfiguration {
private static final String REALM_ROLE_USER = "user";
@Bean
public SecurityActorIdResolver securityActorIdResolver() {
return new SecurityActorIdResolver();
}
@Bean
public SecurityAuditTrailWriter securityAuditTrailWriter(SecurityActorIdResolver securityActorIdResolver) {
return new SecurityAuditTrailWriter(securityActorIdResolver);
}
@Bean
public SecurityExceptionHandler securityExceptionHandler(
@Qualifier("handlerExceptionResolver") HandlerExceptionResolver handlerExceptionResolver,
SecurityAuditTrailWriter securityAuditTrailWriter
) {
return new SecurityExceptionHandler(handlerExceptionResolver, securityAuditTrailWriter);
}
@Bean
public Converter<Jwt, Collection<GrantedAuthority>> keycloakGrantedAuthoritiesConverter() {
return new KeycloakGrantedAuthoritiesConverter();
}
@Bean
public KeycloakAuthenticatedUserFactory keycloakAuthenticatedUserFactory() {
return new KeycloakAuthenticatedUserFactory();
}
@Bean
public Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter(
Converter<Jwt, Collection<GrantedAuthority>> keycloakGrantedAuthoritiesConverter,
KeycloakAuthenticatedUserFactory keycloakAuthenticatedUserFactory
) {
return new KeycloakJwtAuthenticationConverter(
keycloakGrantedAuthoritiesConverter,
keycloakAuthenticatedUserFactory
);
}
@Bean
public SecurityFilterChain securityFilterChain(
HttpSecurity http,
Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter,
SecurityExceptionHandler securityExceptionHandler
) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
"/actuator/health",
"/actuator/health/**",
"/livez",
"/readyz",
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs/**"
).permitAll()
.requestMatchers(HttpMethod.GET, "/api/v1/auth/me").hasRole(REALM_ROLE_USER)
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter))
.authenticationEntryPoint(securityExceptionHandler)
.accessDeniedHandler(securityExceptionHandler)
)
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(securityExceptionHandler)
.accessDeniedHandler(securityExceptionHandler)
)
.build();
}
}