简体   繁体   中英

Changing the login service URL in spring security

Hi I have implemented Spring security in my spring boot web application with JWT filters. But the default authentication is happening at url http://localhost:8080/login . How to change /login to some url I need like /rest/auth/login ?

My WebSecurity class is

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;

public WebSecurity( UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder )
{
    this.userDetailsService = userDetailsService;
    this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}

@Override
protected void configure( HttpSecurity http ) throws Exception
{
    http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
            .antMatchers("/static/*").permitAll().antMatchers("/").permitAll()
            /* .anyRequest().authenticated() */.and()
            .addFilter(new JWTAuthenticationFilter(authenticationManager()))
            .addFilter(new JWTAuthorizationFilter(authenticationManager()));
}

@Override
public void configure( AuthenticationManagerBuilder auth ) throws Exception
{
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Override
public void configure( org.springframework.security.config.annotation.web.builders.WebSecurity web )
        throws Exception
{

    web.ignoring().antMatchers("/static/**");
}

@Bean
CorsConfigurationSource corsConfigurationSource()
{
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
    return source;
}
}

I have a login page in my resource folder under static directory. The way Spring security works is, when user sends userName and password from the form, client has to send those credentials to /login path in the server, so that spring security verifies those credentials and creates token. But I want to change that default path /login to /rest/auth/login

You need to tweak the WebSecurityConfig.java and JWTAuthenticationFilter .

@Override
protected void configure( HttpSecurity http ) throws Exception
{

    http.csrf().disable()

            .authorizeRequests()

            .antMatchers("/rest/noauth/**").permitAll()

            .antMatchers("/rest/login").permitAll()

            .antMatchers("/rest/logout").permitAll()

            .antMatchers("/src/**").permitAll()

            .antMatchers("/v2/api-docs/**", "/configuration/ui/**", "/swagger-resources/**",
                    "/configuration/security/**", "/swagger-ui.html/**", "/webjars/**")
            .permitAll()

            .anyRequest().authenticated()

            .and()

            .logout().addLogoutHandler(logoutHandler).logoutSuccessHandler(logoutSuccessHandler)
            .logoutUrl("/rest/logout")

            .and()

            .addFilterBefore(
                    new JWTAuthenticationFilter("/rest/login",
                    UsernamePasswordAuthenticationFilter.class)

            .addFilterBefore(new JWTAuthorizationFilter(authenticationManager(), authTokenModelRepository),
                    UsernamePasswordAuthenticationFilter.class);

    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

and make your JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter which has a constructor which takes the filterProcessingURl and I passed /rest/login as the parameter.

public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

private static final Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);

private AuthenticationManager authenticationManager;
private TokenService tokenService;
private UserModel credentials;

private RefreshTokenService refreshTokenService;
private AuthTokenModelRepository authTokenModelRepository;
private UserModelRepository userModelRepository;

public JWTAuthenticationFilter( String loginUrl, AuthenticationManager authenticationManager,
        TokenService tokenService, RefreshTokenService refreshTokenService,
        AuthTokenModelRepository authTokenModelRepository, UserModelRepository userModelRepository )
{
    super(new AntPathRequestMatcher(loginUrl));

}

After the above configuration, the JWTAuthenticationFilter will be executed for the request /rest/login .

In your AuthenticationFilter you can call setFilterProcessesUrl during construction, example:

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

   private AuthenticationManager authenticationManager;

   public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
      this.authenticationManager = authenticationManager;

      setFilterProcessesUrl("/api/v1/tokens"); // <--- like this
   }

   ...

Hope it helps.

Just to complement Jordy Baylac's answer: in Kotlin I was struggling how to set the filter once I'm injecting the dependencies via main constructor. My solution was do something like this:

class AuthenticationFilter(
    authenticationManager: AuthenticationManager?,
    private var jwtUtilsComponent: JwtUtilsComponent,
) : UsernamePasswordAuthenticationFilter() {
    private val authManager: AuthenticationManager? = authenticationManager

    init {
        setFilterProcessesUrl("/${ApiProperties.BASE_PATH}/login")
    }
    
    // more code
}

then it worked very well.

In the configure method try to add loginProcessungUrl() method. You can set the value in the parameter

.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.loginProcessingUrl(LOGIN_URL);

You need to provide the url to the login page and the url that would process the authentication. This can be done by overriding the method like this:

    @Override
    protected void configure( HttpSecurity http ) throws Exception
    {
        http.cors().and().csrf().disable().
        authorizeRequests().
        antMatchers(HttpMethod.POST, "/rest/auth/**").
        permitAll()           
       .antMatchers("/static/*").permitAll()  
       .antMatchers("/").permitAll()
       .and().formLogin().
       /*This is where the juice is*/
       loginPage("/login").loginProcessingUrl("/rest/auth/login")
       /* .anyRequest().authenticated() */.and()
       .addFilter(new JWTAuthenticationFilter(authenticationManager()))
       .addFilter(new JWTAuthorizationFilter(authenticationManager()));
        }

The loginPage("/login") can be replaced with the route to your static login page while the loginProcessingUrl is the url of the controller that processes your login logic. Ensure that controllers exist for both /login and /loginProcesingUrl.

Modify "HttpSecurity", as follows, example:

@Override
protected void configure( HttpSecurity http ) throws Exception {
http.cors().and().csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, "/rest/auth/**").permitAll()
        .antMatchers("/static/*").permitAll().antMatchers("/").permitAll()
        /* .anyRequest().authenticated() */
        .and()
             .formLogin()
             .loginPage("/login")
             .loginProcessingUrl("/rest/auth/login")
             .permitAll()
        .and()
             .logout()
             .permitAll();
        .and()
             .addFilter(new JWTAuthenticationFilter(authenticationManager()))
             .addFilter(new JWTAuthorizationFilter(authenticationManager()));
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM