I have spring config, where i am saving spring session in redis.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.cors(Customizer.withDefaults())
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/api/v1/auth/register/**", "/api/v1/auth/login" , "/api/v1/profile/**").permitAll();
auth.requestMatchers("/api/v1/profile").authenticated();
auth.anyRequest().authenticated();
})
.sessionManagement(sessionManagement -> sessionManagement
.sessionCreationPolicy(IF_REQUIRED) //
.sessionFixation(SessionManagementConfigurer.SessionFixationConfigurer::newSession) //
.maximumSessions(1) //
.sessionRegistry(sessionRegistry())
)
//.exceptionHandling((ex) -> ex.authenticationEntryPoint(this.authEntryPoint))
.logout(out -> out
.logoutUrl("/api/v1/auth/logout")
.invalidateHttpSession(true) // Invalidate all sessions after logout
.deleteCookies("JSESSIONID")
.addLogoutHandler(new CustomLogoutHandler(this.redisIndexedSessionRepository))
.logoutSuccessHandler((request, response, authentication) ->
SecurityContextHolder.clearContext()
)
)
.build();
}
I want "/api/v1/auth/profile/**"
route to be accessible for anyone, without authentication, however i want "/api/v1/auth/profile"
to be accessible only for authenticated users.
Using this config, however i am able to still access /api/v1/auth/profile` authenticated, what i have noticed, that if i use
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
authentication.getPrincipal();
The authentication.isAuthenticated()
results in true and authentication.getPrincipal()
returns "anonymousUser" , could that be the reason why it passes to the route even tho authentication is required?
Thanks for help
2
Answers
The reason why "/api/v1/auth/profile" is accessible even without authentication is because Spring Security treats it as a wildcard path that includes "/api/v1/auth/profile/**", thus permitting access to any sub-paths under "/api/v1/auth/profile".
To resolve this issue, you can rearrange your "authorizeHttpRequests" configuration to explicitly permit access to "/api/v1/auth/profile" only for authenticated users, and allow "/api/v1/auth/profile/**" for anyone. Here’s how you can modify your configuration:
With this change, "/api/v1/auth/profile/**" will remain accessible to anyone, while "/api/v1/auth/profile" will only be accessible to authenticated users.
Regarding your observation about the "Authentication" object having "isAuthenticated()" as "true" and the "principal" being "anonymousUser", this is the default behavior when a request is not authenticated. Spring Security automatically creates an anonymous authentication token to represent unauthenticated users. So even though "isAuthenticated()" returns "true", it doesn’t necessarily mean that the user is authenticated in the context of your application’s authentication mechanism.
This minimal configuration works for me and should work for you as well.
To access
/profile
itself I need to be authenticated. To access/profile/nested
I don’t.If I swap the order to
then even the
/profile
endpoint is accessible by everyone. So the order matters.