I am trying to figure out how to implement endpoint user security via https://spring.io/guides/topicals/spring-security-architecture/#_working_with_threads and How to allow a User only access their own data in Spring Boot / Spring Security? However, @AuthenticationPrincipal
, Authentication
, and Principal
when used in this manner. What am I missing? I am certain I have the right secrets/Jwt set up because the authentication itself works, I just cant use the annotation to pull the information I want
SecurityConfig.class
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {
private static final String[] AUTH_WHITELIST = {
// -- Swagger UI v2
"/v2/api-docs",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**",
// -- Swagger UI v3 (OpenAPI)
"/v3/api-docs/**",
"/swagger-ui/**"
// other public endpoints of your API may be appended to this array
};
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// Our public endpoints
.antMatchers("/**/openapi.json").permitAll()
.antMatchers("/api/ims/auth/**").permitAll()
.antMatchers(AUTH_WHITELIST).permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
// Used by JwtAuthenticationProvider to decode and validate JWT tokens
@Bean
public JwtDecoder jwtDecoder() {
SecretKey secretKey = new SecretKeySpec("INSERTSECRETHERE".getBytes(), "HMACSHA256");
return NimbusJwtDecoder.withSecretKey(secretKey).macAlgorithm(MacAlgorithm.HS256).build();
}
}
ConnectionController.class
@Path("connection/v1")
@SecurityScheme(name = SWAGGER_AUTH_NAME, type = HTTP, scheme = SWAGGER_AUTH_SCHEME, in = HEADER)
@Tag(name = "Connection Controller", description = "Manage connection resources")
@RestController
public class ConnectionController {
private final ConnectionService connectionService;
@Inject
public ConnectionController(final ConnectionService connectionService)
{
this.connectionService = connectionService;
}
@GET
@Path("/user/{userId}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(description = "Retrieve connections by userId")
//@PreAuthorize("authentication.principal.claims.userId.equals(#userId)")
public List<ConnectionDto> getConnectionsByUserId(@PathParam("userId") final String userId, @Parameter(hidden = true) @AuthenticationPrincipal Jwt authentication)
{
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication1 = context.getAuthentication();
Object jwt = context.getAuthentication().getPrincipal();
Assert.hasText(userId, "User id must be provided");
return this.connectionService.getConnectionsByUserId(userId);
}
}
Variables context
, authentication
, and jwt
all return what I anticipate, the last being a Jwt
object, which is exactly what I'd want @AuthenticationPrincipal
to return. However, @AuthenticationPrincipal
, Authentication
, and Principal
all return null from that method.