SecurityConfiguration.java
package org.petify.backend.configuration;
import org.petify.backend.repository.UserRepository;
import org.petify.backend.services.CustomOAuth2UserService;
import org.petify.backend.services.TokenService;
import org.petify.backend.utils.RSAKeyProperties;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfiguration {
@Autowired
private RSAKeyProperties keys;
@Autowired
private CustomOAuth2UserService customOAuth2UserService;
@Autowired
private TokenService tokenService;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private UserRepository userRepository;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authManager() {
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
daoProvider.setUserDetailsService(userDetailsService);
daoProvider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(daoProvider);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/.well-known/jwks.json", "/auth/**", "/login/**", "/oauth2/**").permitAll();
auth.requestMatchers("/admin/**").hasRole("ADMIN");
auth.requestMatchers("/user/**").permitAll();
// auth.requestMatchers("/user/**").hasAnyRole("ADMIN", "USER", "VOLUNTEER", "SHELTER");
auth.requestMatchers("/actuator/health").permitAll();
auth.anyRequest().authenticated();
})
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService))
.successHandler((request, response, authentication) -> {
try {
org.springframework.security.oauth2.core.user.OAuth2User oauth2User =
(org.springframework.security.oauth2.core.user.OAuth2User) authentication.getPrincipal();
Integer userId = oauth2User.getAttribute("userId");
String token = tokenService.generateJwt(authentication);
String frontendUrl = "http://localhost:5173/home?token=" + token + "&userId=" + userId;
response.sendRedirect(frontendUrl);
} catch (Exception e) {
response.sendRedirect("http://localhost:5173/login?error=OAuth2%20authentication%20failed");
}
})
.failureHandler((request, response, exception) ->
response.sendRedirect("http://localhost:5173/login?error=OAuth2%20authentication%20failed")
)
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(keys.getPublicKey()).build();
}
@Bean
public JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(keys.getPublicKey()).privateKey(keys.getPrivateKey()).build();
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
jwtConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return jwtConverter;
}
}