@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(AuthenticationController authenticationController,
AuthorizationController authorizationController,
AuthenticationProvider authenticationProvider) {
return args -> {
Spectator spectator = new Spectator("userdemo", "1234");
Player player = new Player("Khvicha", "Kvaratskhelia"); player.setId(1L);
Map<String, String> credentials = new HashMap<>();
credentials.put("username", spectator.getUsername());
credentials.put("password", spectator.getPassword());
authenticationController.register(credentials);
System.out.println(credentials);
Authentication authentication = authenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(spectator.getUsername(), spectator.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
authorizationController.addNewPlayer(player);
};
}
}
Firstly, I register an user and then before calling controller methods, I authenticate users. In this case player is added successfully. But when I try to do the same with postman I fail.
Below is my security configuration. I don't use WebSecurityConfigurerAdapter
or JWT authentication.
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
private static final String SPECTATOR = Role.SPECTATOR.name();
private static final String COACH = Role.COACH.name();
private static final String ADMIN = Role.ADMIN.name();
private static final String[] WHITE_LIST = {
"/api/v1/users/auth/**",
};
private final AuthenticationProvider authProvider;
@Autowired
public SecurityConfiguration(AuthenticationProvider authProvider) {
this.authProvider = authProvider;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/users/auth/**").permitAll()
.requestMatchers("/api/v1/home/players/create").hasAuthority(SPECTATOR)
.anyRequest().authenticated())
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
.authenticationProvider(authProvider);
return http.build();
}
}
I tried to add form based authentication
.formLogin(form -> form
.loginPage("/login")
.loginProcessingUrl("/api/v1/users/auth/login")
.defaultSuccessUrl("/homepage", true)
.failureUrl("/login?error=true"));
But it didn't work either. I either got infinite redirection loop or 403 error even tho I definitely entered correct credentials.
You are on the right track regarding adding form login, though I think that's probably not what you are looking for, considering you are publishing an API.
If you are not using JWT, then there are other options for API authentication like HTTP Basic. Consider the following alternative setup:
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoreRequestMatchers(new RequestHeaderRequestMatcher("Postman-Token")))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/users/auth/**").permitAll()
.requestMatchers("/api/v1/home/players/create").hasAuthority(SPECTATOR)
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults());
return http.build();
}
When you do this, marking the session as stateless is often unnecessary since the authentication filter for HTTP Basic doesn't access the session in the first place.
Then, when testing in Postman, set up the Authorization
header with HTTP Basic and the username/password credentials.
Finally, instead of a custom authentication provider, consider a custom UserDetailsService
; if you share your AuthenticationProvider
implementation, I'll happily update my answer with more targeted guidance there.