在捕获之前 x509 验证失败
x509 validation fails before it can be captured
我有一个 Spring 引导应用程序,它使用 x509 身份验证进一步根据数据库验证用户。当用户访问站点时,内部 Spring 代码调用 loadUserByUsername 方法,该方法反过来调用数据库。这一切都发生在控制器意识到任何事情发生之前。如果找不到用户,它会抛出 EntityNotFoundException 并在用户的浏览器上显示堆栈跟踪。
我正在使用 Spring 引导程序。控制器具有捕获异常的代码和 return 一条 'Not Authorized' 消息,但这发生在很久以前。有没有其他人看到过这个,你有解决方法吗?
@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 公开。
我有一个 Spring 引导应用程序,它使用 x509 身份验证进一步根据数据库验证用户。当用户访问站点时,内部 Spring 代码调用 loadUserByUsername 方法,该方法反过来调用数据库。这一切都发生在控制器意识到任何事情发生之前。如果找不到用户,它会抛出 EntityNotFoundException 并在用户的浏览器上显示堆栈跟踪。
我正在使用 Spring 引导程序。控制器具有捕获异常的代码和 return 一条 'Not Authorized' 消息,但这发生在很久以前。有没有其他人看到过这个,你有解决方法吗?
@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 公开。