I'm using Spring Boot, Spring Security, Spring Data REST, Hibernate. I'm creating a REST API server.
I configured security to access my REST API as:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@CrossOrigin(origins = "*")
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private TenantFilter tenantFilter;
@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(User.PASSWORD_ENCODER);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public JwtAuthenticationTokenFilter jwtTokenFilter() throws Exception {
return new JwtAuthenticationTokenFilter();
}
@Bean
public CookieAuthFilter cookieAuthFilter() throws Exception {
return new CookieAuthFilter();
}
@Bean
public CustomWebAuthenticationDetailsSource customWebAuthenticationDetailsSource() {
return new CustomWebAuthenticationDetailsSource();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//********************************************************************
// PERMIT OPTIONS
//********************************************************************
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
//********************************************************************
//WEBSOCKET
//********************************************************************
.antMatchers("/socket/**").permitAll()
.antMatchers("/images/**").permitAll()
.antMatchers("/resources/templates/**").permitAll()
.antMatchers("/api/v1/notifications/**").permitAll()
//********************************************************************
// SWAGGER
//********************************************************************
.antMatchers("/v2/api-docs", "/swagger-accounts/configuration/ui", "/swagger-accounts", "/swagger-accounts/configuration/security",
"/swagger-ui.html", "/webjars/**", "/swagger-resources/**").permitAll()
.antMatchers("/api/v1/").permitAll()
.antMatchers("/api/v1/auth/**").permitAll()
.antMatchers("/api/v1/formLogin/**").permitAll()
.antMatchers("/api/v1/logout").permitAll()
.antMatchers("/api/v1/agents/verifyEmail").permitAll()
.antMatchers("/api/v1/agents/**/verificationToken").permitAll()
.antMatchers("/api/v1/agents/**/resetPassword").permitAll()
.antMatchers("/api/v1/agents/**/verifyPasswordReset").permitAll()
.antMatchers("/api/v1/agents/**/changePassword").permitAll()
.antMatchers("/api/v1/errors/**").permitAll()
.antMatchers("/api/v1/verifyCaptcha").permitAll()
.antMatchers("/api/v1/ping").permitAll()
.antMatchers("/api/v1/tenants/**").permitAll()
// all other endpoints are authenticated
.antMatchers("/**").authenticated()
// global settings
.and()
.csrf()
.disable();
http.formLogin().loginPage("/login").permitAll();
// Custom JWT based security filter
http.addFilterBefore(tenantFilter, UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(cookieAuthFilter(), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl().disable();
}
}
The goal I want to get is:
show a form login when the user try to access to the url like http://myhost/swagger-ui.html#/ in order to be able to use swagger easily
avoid form login when the server is called with a REST call (through Angular or Postman or whatever). In fact, otherwise if the auth fails, the server replies with the html code of the login page
is there a way to accomplish this with Spring, without turning off formLogin()?
Other configuration looks fine
If you notice swagger related urls are also are marked as permitAll().
Just remove permitAll part of swagger and add this in last as authenticated() something like this
.antMatchers("/v2/api-docs", "/swagger-accounts/configuration/ui", "/swagger-accounts", "/swagger-accounts/configuration/security",
"/swagger-ui.html", "/webjars/**", "/swagger-resources/**").authenticated()
For REST calls just see if they are added in permitAll()
Also Note: The order of the rules matters and the more specific rules should go first
eg
.antMatchers("/admin/**").authenticated()
.antMatchers("/admin/login").permitAll()
Here /admin/login
will also be authenticated.
Look at Combining basic authentication and form login for the same REST Api , I believe it meets your requirement.
The only thing I think you may need to change is in ApiWebSecurityConfigurationAdapter
since you only ask 403, the content should look like below ( hasRole(String...)
could be replaced by authenticated()
if you don't like it's too strict).
http.antMatcher("/api/**").authorizeRequests().anyRequest().hasRole("ADMIN")
I don't know if or how you solved this, but i was looking for something similar. So for anybody who is also looking for this here are my thoughts:
You an configure 2 HttpSecurity elements . So you have extends the WebSecurityConfigurerAdapter 2 times. Make your endpoints like this:
Then in one security config confiugre that /view/ with .formlogin() In the other security don't configure the .formlogin()
An example of 2 securityConfigs in one app can be found here: https://www.baeldung.com/spring-security-two-login-pages However in that article they use it to show 2 different login pages, you could just use this to not show a formlogin in one case...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.