我有一个使用Spring Security进行身份验证的RESTful Web服务。我已将自定义AuthenticationProvider
注册到我的应用程序,该应用程序将其authenticate()
业务逻辑委派给远程服务,该服务可能不可用。当远程服务不可用时,我希望呼叫能够*返回503 Service Unavailable
。
Spring Security会按预期处理403 Forbidden
,但我想在某个地方添加503
逻辑。 AuthenticationProvider
接口可以抛出运行时AuthenticationException
,但它及其后代由ProviderManager
处理。
这是我的WebSecurityConfigurer:
// how do I hook this into 'http'???
@Autowired
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
protected void configure(HttpSecurity http) throws Exception {
http
.authenticationProvider(myAuthenticationProvider)
.httpBasic()
.and()
.exceptionHandling()
.authenticationEntryPoint(myAuthenticationEntryPoint)
.accessDeniedHandler(myAccessDeniedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
...
如果我有自定义HttpSecurity
,如何配置503
以返回所需的AuthenticationProvider
?
* - 诚然,这是一个极端的案例。
答案 0 :(得分:1)
为您的Web服务身份验证注册 AbstractAuthenticationProcessingFilter ,并从那里尝试进行身份验证。您可以在同一过滤器类中配置失败处理程序。
public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {
private static Logger logger = LoggerFactory.getLogger(AjaxLoginProcessingFilter.class);
private final AuthenticationSuccessHandler successHandler;
private final AuthenticationFailureHandler failureHandler;
private final ObjectMapper objectMapper;
public AjaxLoginProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler,
AuthenticationFailureHandler failureHandler, ObjectMapper mapper) {
super(defaultProcessUrl);
this.successHandler = successHandler;
this.failureHandler = failureHandler;
this.objectMapper = mapper;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
if (!HttpMethod.POST.name().equals(request.getMethod()) || !WebUtil.isAjax(request)) {
if(logger.isDebugEnabled()) {
logger.debug("Authentication method not supported. Request method: " + request.getMethod());
}
throw new AuthMethodNotSupportedException("Authentication method not supported");
}
LoginRequest loginRequest = objectMapper.readValue(request.getReader(), LoginRequest.class);
if (StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isBlank(loginRequest.getPassword())) {
throw new AuthenticationServiceException("Username or Password not provided");
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
return this.getAuthenticationManager().authenticate(token);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
successHandler.onAuthenticationSuccess(request, response, authResult);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, failed);
}
}
<强> LoginRequest.java 强>
public class LoginRequest {
private String username;
private String password;
@JsonCreator
public LoginRequest(@JsonProperty("username") String username, @JsonProperty("password") String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
身份验证提供程序中的身份验证失败并实现AuthenticationFailureHandler,然后更改响应状态。
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
}
您可以指定何时在故障处理程序中抛出哪个状态。
答案 1 :(得分:1)
我能够通过使用2个自定义组件来解决它:
MyUnavailableException
(扩展AuthenticationException
)Custom503AuthenticationEntryPoint
public class Custom503AuthenticationEntryPoint implements AuthenticationEntryPoint { public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException { if (ex instanceof MyUnavailableException) { response.sendError(HttpStatus.SERVICE_UNAVAILABLE.value(), HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase()); } ...