2016-12-30 13 views
0

私は、Spring Securityを使用して認証するRESTfulなWebサービスを持っています。私はAuthenticationProviderというカスタムをそのアプリケーションのauthenticate()ビジネスロジックをリモートサービスに委譲するアプリケーションに登録しました。これは利用できない可能性があります。リモートサービスが利用できないときは、503 Service Unavailableを返すことができるようにしたい。Springセキュリティ:503サービスを返す方法はありませんか?

スプリングセキュリティハンドルは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() 
    ... 

私はカスタムAuthenticationProviderを持って与えられ、希望503を返すようにHttpSecurityを設定するにはどうすればよいですか?

* - 確かに、これはコーナーケースです。

+0

ControllerAdvice'が適用される@あなたは 'ControllerAdvice –

+0

を作成することができますSpring MVCのみに適用されます。 Spring Security認証レイヤは、ControllerAdviceの前に発生します。 –

答えて

1

登録AbstractAuthenticationProcessingFilter Webサービス認証のために、そこから自動化を試みてください。障害ハンドラは、同じフィルタクラスで構成できます。

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

} 

エラーハンドラでどのステータスをスローするかを指定できます。

+0

'AuthenticationFailureHandler'は' HttpSecurity'でどこに登録されますか? –

+0

これは、使用しているログインメカニズムによって異なります。フォームのログインには、_http.formLogin()として設定することができます。failureHandler()_ –

+0

私は非 'formLogin'制約を追加しました。それは_only_アクセサーのようです。それ以外はすべてデフォルトの 'SimpleUrlAuthenticationFailureHandler'を使います。 –

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()); 
     } 
... 
関連する問題