X509验证在可以捕获之前失败



我有一个弹簧引导应用程序,使用X509身份验证,该身份验证进一步验证用户针对数据库。当用户访问该站点时,内部弹簧代码调用了LoadUserByusername方法,该方法依次进行数据库调用。这一切发生在控制器意识到发生任何事情之前。如果找不到用户,它将抛出EntityNotFoundException并在用户的浏览器上显示堆栈跟踪。

我正在使用春季启动器。控制器具有捕获异常的代码并返回"未授权"消息,但这在很久以前就会发生。还有其他人看过这个吗,你有解决方法吗?

@Service
public class UserService implements UserDetailsService {
    public UserDetails loadUserByUsername(String dn) {
        ApprovedUser details = auService.getOne(dn);
        if (details ==  null){
            String message = "User not authorized: " + dn;
            throw new UsernameNotFoundException(message);
        }
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        if (details.isAdminUser()){
            authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN_USER"));
        }
        return new AppUser(dn, "", authorities);
    }

通常,您通常会使用AuthenticationFailureHandler封装由AuthenticationException触发的逻辑。X509AuthenticationFilter通常会调用PreAuthenticatedAuthenticationProvider进行身份验证,这又会从UserDetailsService调用loadUserByUsername(...)方法。UserDetailsService抛出的任何AuthenticationException均被过滤器捕获,并且控件将传递给注册的AuthenticationFailureHandler。这包括UsernameNotFoundException

但是,如果您使用的是X509Configurer,(http.x509()(,则无法直接在过滤器上设置处理程序。因此,一旦抛出了例外,X509AuthenticationFilter就会抓住它,发现没有默认处理程序,然后将请求传递给过滤器链中的下一个过滤器。

解决此问题的一种方法可能是提供自定义X509AuthenticationFilter

WebSecurityConfigurerAdapter中:

@Autowired
private AuthenticationFailureHandler customFailureHandler;
@Autowired
private UserService customUserService;
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
} 
protected void configure(HttpSecurity http) throws Exception {
    ...
    http.x509().x509AuthenticationFilter(myX509Filter())
    .userDetailsService(customUserService)
    ...
}
private X509AuthenticationFilter myX509Filter() {
    X509AuthenticationFilter myCustomFilter = new X509AuthenticationFilter();
    myCustomFilter.setAuthenticationManager(authenticationManagerBean());
    ...
    myCustomFilter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
    myCustomFilter.setAuthenticationFailureHandler(customFailureHandler);
    return myCustomFilter;
}

然后,您可以编写自己的AuthenticationFailureHandler实现并将其公开为Bean。

最新更新