不能第二次打电话给auth提供商

时间:2018-04-10 17:22:51

标签: java spring security spring-boot spring-security

我正在使用spring security进行身份验证

@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();
}

这很好用。当我点击/ api / login我能够使用基本身份验证

但是在第一次成功验证后,我可以使用/ api / login而无需身份验证。

第二次没有带我去授权提供商。第一次控制是在那里,但不是第二次。

2 个答案:

答案 0 :(得分:0)

会话在您登录时创建。会话将一直处于活动状态,直到您退出(销毁会话)或时间到期为止。
example

修改 Spring应用程序有一些与session相关的重要设置。 第一个是会话创建策略(默认为IF_REQUIRED - 如果与请求链接的会话已经存在,则不会销毁并再次创建)。 会话保存在cookie中 - 您可以检查它是否达到f12。 申请"检查" cookie是否存在于请求中。当你进入登录页面时,有两种情况:

  • 你没有会话 - >出现登录弹出窗口,您可以登录,
  • 您有会话,因为SecurityContextHolder包含有关当前会话的信息。

它是如何运作的?

当您使用.httpBasic()时,Spring Security会注册BasicAuthenticationFilter。在方法doFilterInternal中,您可以看到:

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);
            }

首次登录成功后,将设置身份验证。 当您尝试再次登录时,authenticationIsRequired方法返回false。为什么? 看看来源:

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;
    }

正如您所看到的,在SecurityContextHolder上调用getAuthhentication返回上一个请求中设置的对象。 抱歉我的英语不好。

更新:您可以使用" / logout"使会话无效网址。

答案 1 :(得分:0)

注册两个WebSecurity配置:

aidl

休息:

@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();
    }

}

小心:有antMatcher(...)和antMatcher s (...)方法。

更新:类似问题&解决方案here