简体   繁体   中英

can not call auth provider for second time hit

I am using spring security for authentication

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {      
    auth.authenticationProvider(authProvider).authenticationProvider(secondaryAuthProvider) ;
}


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



    http.csrf().disable().authorizeRequests()
    .antMatchers("/login").hasAnyRole("ADMIN","VISITOR").and().
    formLogin().defaultSuccessUrl("/login").failureUrl("/")
    .loginPage("/login").usernameParameter("username").passwordParameter("password").failureUrl("/").
    and().logout().permitAll().and().exceptionHandling().accessDeniedPage("/403").and()
    .authorizeRequests().antMatchers("/resources/**").permitAll().and().authorizeRequests().
    antMatchers("/api/**").authenticated().and().httpBasic().realmName("MY_TEST_REALM").
    authenticationEntryPoint(getBasicAuthEntryPoint());
}

@Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
    return new CustomBasicAuthenticationEntryPoint();
}

This is working fine. When i hit /api/login i am able to use basic authentication

But after first successful authentication I am able to use /api/login without authentication.

It is not taking me to auth provider at second time. First time control is going there but not second time.

Session is created when you log in. Session will be active until you logout (destroy session), or when time expire.
See example

EDIT: Spring application have a few important settings associated with session. The first one is session creation policy (by default IF_REQUIRED - if session linked with request already exists it will be not destroyed and created again). Session is saved in cookie - you can check it hitting f12. Application "check" does cookie exist in request. When you go to login page there are two cases:

  • you don't have session -> login popup appears, you can log in,
  • you have session because SecurityContextHolder contain information about current session.

How does it work?

When you use .httpBasic(), Spring Security registers BasicAuthenticationFilter. In method doFilterInternal you can see:

if (authenticationIsRequired(username)) {
                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                        username, tokens[1]);
                authRequest.setDetails(
                        this.authenticationDetailsSource.buildDetails(request));
                Authentication authResult = this.authenticationManager
                        .authenticate(authRequest);

                if (debug) {
                    this.logger.debug("Authentication success: " + authResult);
                }

                SecurityContextHolder.getContext().setAuthentication(authResult);

                this.rememberMeServices.loginSuccess(request, response, authResult);

                onSuccessfulAuthentication(request, response, authResult);
            }

After success first login, authentication is set. When you try to log in again authenticationIsRequired method returns false. Why? Look at the source:

private boolean authenticationIsRequired(String username) {
        // Only reauthenticate if username doesn't match SecurityContextHolder and user
        // isn't authenticated
        // (see SEC-53)
        Authentication existingAuth = SecurityContextHolder.getContext()
                .getAuthentication();

        if (existingAuth == null || !existingAuth.isAuthenticated()) {
            return true;
        }

        // Limit username comparison to providers which use usernames (ie
        // UsernamePasswordAuthenticationToken)
        // (see SEC-348)

        if (existingAuth instanceof UsernamePasswordAuthenticationToken
                && !existingAuth.getName().equals(username)) {
            return true;
        }

        // Handle unusual condition where an AnonymousAuthenticationToken is already
        // present
        // This shouldn't happen very often, as BasicProcessingFitler is meant to be
        // earlier in the filter
        // chain than AnonymousAuthenticationFilter. Nevertheless, presence of both an
        // AnonymousAuthenticationToken
        // together with a BASIC authentication request header should indicate
        // reauthentication using the
        // BASIC protocol is desirable. This behaviour is also consistent with that
        // provided by form and digest,
        // both of which force re-authentication if the respective header is detected (and
        // in doing so replace
        // any existing AnonymousAuthenticationToken). See SEC-610.
        if (existingAuth instanceof AnonymousAuthenticationToken) {
            return true;
        }

        return false;
    }

As you can see getAuthhentication invoked on SecurityContextHolder return object set in previous request. Sorry for my bad English.

UPDATE: you can invalidate session using "/logout" url.

Register two WebSecurity configurations:

@Configuration
@EnableWebSecurity
@Order(1)
public class StatefulConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider).authenticationProvider(secondaryAuthProvider) ;
    }


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

        http.csrf().disable().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and()
       .antMatcher("/web/*").authorizeRequests()
                .antMatchers("/*").hasAnyRole("ADMIN","VISITOR").and().
                formLogin().defaultSuccessUrl("/web/login").failureUrl("/web/error").loginPage("/web/login").usernameParameter("username").passwordParameter("password").failureUrl("/").
                and().logout().logoutUrl("/web/logout").permitAll().and().exceptionHandling().accessDeniedPage("/403").and()
                .authorizeRequests().antMatchers("/resources/**").permitAll();
    }

}

And for rest:

@Configuration
@Order(2)
public class StatelessConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider).authenticationProvider(secondaryAuthProvider) ;
    }


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

        http.csrf().disable().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
           .antMatcher("/api/*").authorizeRequests()
                .antMatchers("/api/**").authenticated().and().httpBasic().realmName("MY_TEST_REALM").
  authenticationEntryPoint(getBasicAuthEntryPoint());
}

    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }

}

Be careful: there are antMatcher(...) and antMatcher s (...) methods.

UPDATE: similar problem & solution here

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