Spring 当使用多个AuthenticationProvider时,如何从PreAuthenticationDauthenticationProvider重定向UsernameNotFoundException?

Spring 当使用多个AuthenticationProvider时,如何从PreAuthenticationDauthenticationProvider重定向UsernameNotFoundException?,spring,authentication,spring-security,authorization,pre-authentication,Spring,Authentication,Spring Security,Authorization,Pre Authentication,使用Spring Security 4.02,当使用多个AuthenticationProviders时,是否有人可以帮助我处理用户名未发现异常中的预验证身份验证提供程序以使经过验证的请求具有正确的头,但未经授权,是否发送到特定的URL而不是表单登录页 让我进一步解释一下,为了访问一个由代理背后的SSO保护的web应用程序,我试图实现什么。并非所有通过SSO身份验证的用户都可以访问此应用。因此,我需要考虑3种访问场景: 已验证用户(存在标题)已授权(用户名/角色存在于应用程序的数据库中) 已验证

使用Spring Security 4.02,当使用多个
AuthenticationProviders
时,是否有人可以帮助我处理
用户名未发现异常
中的
预验证身份验证提供程序
以使经过验证的请求具有正确的头,但未经授权,是否发送到特定的URL而不是表单登录页

让我进一步解释一下,为了访问一个由代理背后的SSO保护的web应用程序,我试图实现什么。并非所有通过SSO身份验证的用户都可以访问此应用。因此,我需要考虑3种访问场景:

  • 已验证用户(存在标题)已授权(用户名/角色存在于应用程序的数据库中)
  • 已验证用户(存在标题)未经授权(用户名/角色在应用程序的数据库中不存在)
  • 应用数据库中存在用户名/角色的未经身份验证的用户
  • 访问网站时的操作应为:

  • 经过身份验证/授权的用户直接进入目标URL
  • 已验证/未授权的用户被重定向到错误/信息页面
  • 未经身份验证的用户将重定向到表单登录页进行身份验证
  • 在我当前的配置中,场景1和3似乎可以按预期工作。对于场景2,我尝试将
    RequestHeaderAuthenticationFilter#setExceptionIfHeaderMissing
    设置为true和false

    如果
    setExceptionIfHeaderMissing=false
    ,则通过
    ExceptionTranslationFilter
    处理已验证/未授权的请求,其中抛出
    AccessDeniedException
    ,并将用户重定向到表单登录页面

    如果
    setExceptionIfHeaderMissing=true
    ,则经过身份验证/未经授权的请求会遇到来自
    AbstractPreAuthenticationdProcessingFilter.DoAuthentication
    PreAuthenticationdCredentialsNotFoundException
    ,并返回HTTP 500

    所以我读了又读了Spring安全参考资料和api文档,浏览了整个网络,只是不太明白我需要做什么。我想我需要启用某种过滤器或处理程序来捕获带有重定向响应的
    PreAuthenticatedCredentialsNotFoundException
    。但我似乎不知道如何用所有可用的spring工具实现这一点。有人能提供一些细节吗?非常感谢

    以下是我的配置:

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    
        private static final String AUTHENTICATION_HEADER_NAME = "PKE_SUBJECT";
    
        @Autowired
        CustomUserDetailsServiceImpl customUserDetailsServiceImpl;
    
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
            auth.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER").and()
                .withUser("admin").password("password").roles("USER", "ADMIN");
            auth.userDetailsService(customUserDetailsServiceImpl);
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().and()
                .authorizeRequests()
                    .antMatchers("/javax.faces.resource/**", "/resources/**", "/templates/**", "/public/**").permitAll()                
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .permitAll()
                    .and()
                .logout()
                    .logoutSuccessUrl("/public/welcome.xhtml")
                    .and()
                .addFilter(requestHeaderAuthenticationFilter());    
        }
    
        @Bean PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() throws Exception {
            PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
            provider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
            return provider;
        }
    
        @Bean
        public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception {
            RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
            filter.setPrincipalRequestHeader(AUTHENTICATION_HEADER_NAME);
            filter.setAuthenticationManager(authenticationManagerBean());
            filter.setExceptionIfHeaderMissing(true);
            return filter;
        }
    
        @Bean
        public UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> 
                userDetailsServiceWrapper() throws Exception {
    
            UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper 
                    = new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>();
            wrapper.setUserDetailsService(customUserDetailsServiceImpl);
            return wrapper;
        }
    }
    
    @配置
    @启用Web安全性
    @EnableGlobalMethodSecurity(Prespenabled=true)
    公共类SecurityConfig扩展了WebSecurity配置适配器{
    私有静态最终字符串身份验证\u头\u NAME=“PKE\u主题”;
    @自动连线
    CustomUserDetailsServiceImpl CustomUserDetailsServiceImpl;
    @自动连线
    public void configureGlobal(AuthenticationManagerBuilder auth)引发异常{
    auth.authenticationProvider(预验证身份验证提供者());
    auth.inMemoryAuthentication()
    .withUser(“用户”)。密码(“密码”)。角色(“用户”)和()
    .withUser(“管理员”)。密码(“密码”)。角色(“用户”、“管理员”);
    auth.userDetailsService(customUserDetailsServiceImpl);
    }
    @凌驾
    受保护的无效配置(HttpSecurity http)引发异常{
    http.csrf()和()
    .授权请求()
    .antMatchers(“/javax.faces.resource/**”、“/resources/**”、“/templates/**”、“/public/**”).permitAll()
    .anyRequest().authenticated()
    .及()
    .formLogin()
    .permitAll()
    .及()
    .logout()
    .logoutSuccessUrl(“/public/welcome.xhtml”)
    .及()
    .addFilter(requestHeaderAuthenticationFilter());
    }
    @Bean PreAuthenticateAuthenticationProvider PreAuthenticateAuthenticationProvider()引发异常{
    PreAuthenticateAuthenticationProvider=新的PreAuthenticateAuthenticationProvider();
    setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
    退货供应商;
    }
    @豆子
    public RequestHeaderAuthenticationFilter RequestHeaderAuthenticationFilter()引发异常{
    RequestHeaderAuthenticationFilter=新的RequestHeaderAuthenticationFilter();
    filter.setPrincipalRequestHeader(身份验证\头\名称);
    setAuthenticationManager(authenticationManagerBean());
    filter.setExceptionIfHeaderMissing(true);
    回流过滤器;
    }
    @豆子
    公共UserDetailsByNameServiceWrapper
    userDetailsServiceWrapper()引发异常{
    UserDetailsByNameServiceWrapper
    =新的UserDetailsByNameServiceWrapper();
    setUserDetailsService(customUserDetailsServiceImpl);
    返回包装器;
    }
    }
    
    我的自定义用户详细信息服务:

    @Service("customUserDetailsService")
    public class CustomUserDetailsServiceImpl implements UserDetailsService {
    
        @Autowired
        UserRepo userRepo;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            UserDetailDO userDetail = userRepo.getUserDetailById(username);
            if(userDetail == null) {
                throw new UsernameNotFoundException("user is not authorized for this application");         
            }
    
            List<UserRoleDO> roles = userRepo.getRolesByUsername(username);
            List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    
            if(CollectionUtils.isNotEmpty(roles)) {
                for(UserRoleDO role : roles) {
                    SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRole());
                    authorities.add(authority);             
                }
            }
    
            UserDetails user = new User(username, "N/A", authorities);      
            return user;
        }
    }
    
    @Service(“customUserDetailsService”)
    公共类CustomUserDetailsServiceImpl实现UserDetailsService{
    @自动连线
    UserRepo UserRepo;
    @凌驾
    public UserDetails loadUserByUsername(字符串用户名)引发UsernameNotFoundException{
    UserDetailDO userDetail=userRepo.getUserDetailById(用户名);
    if(userDetail==null){
    抛出新的UsernameNotFoundException(“用户未获得此应用程序的授权”);
    }
    列表角色=userRepo.getRolesByUsername(用户名);
    列表权限=新建ArrayList();
    if(CollectionUtils.isNotEmpty(角色)){
    for(UserRoleDO角色:角色){
    SimpleGrantedAuthority=新的SimpleGrantedAuthority(role.getRole());
    权限。添加(权限);
    }
    }
    UserDetails用户=新用户(用户名,“不适用”,权限);
    返回用户;
    }
    }
    
    I r