代码之家  ›  专栏  ›  技术社区  ›  Ayush

无法为第二次命中调用身份验证提供程序

  •  0
  • Ayush  · 技术社区  · 6 年前

    我正在使用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 回复  |  直到 6 年前
        1
  •  1
  •   Aleksander Burzec    6 年前

    注册两个Web安全配置:

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

    休息时:

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

    小心:有蚂蚁匹配器(…)和antMatcher s (…)方法。

    更新时间: 类似问题(&A);解决方案 here

        2
  •  0
  •   Community Egal    4 年前

    会话是在您登录时创建的。会话将处于活动状态,直到您注销(销毁会话)或时间到期。
    看见 example

    编辑: Spring应用程序有一些与会话相关的重要设置。 第一个是会话创建策略(默认情况下,如果需要\u-如果与请求链接的会话已经存在,则不会销毁并再次创建)。 会话保存在cookie中-您可以点击f12检查它。 应用程序“检查”请求中是否存在cookie。当您进入登录页面时,有两种情况:

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

    它是如何工作的?

    当您使用时。httpBasic(),Spring安全寄存器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);
                }
    

    首次登录成功后,将设置身份验证。 当您尝试再次登录时,AuthenticationsRequired方法返回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。 对不起,我英语不好。

    更新:您可以使用“/注销”url使会话无效。