2011-11-29 7 views
5

私はこれを頭で悩ましています: インターセプタを使用していくつかのSOAPヘッダーをチェックすると、インターセプタチェーンを中止できますが、 ?CXF WS、Interceptor:処理を中止してエラーで応答します。

出力に関する障害のスローですが、要求はまだ処理されており、すべてのサービスがメッセージコンテキストでいくつかのフラグをチェックしているとは限りません。

"message.getInterceptorChain()。abort();"で中断する実際にはすべての処理が中断されますが、クライアントには何も返されません。

どうすればいいですか?

+0

残り? –

+0

はい、私はそのフォールトを投げることができます、そして、クライアントは、私が欲しいものですが、依然としてWebServicesでリクエストが処理されているフォールトレスポンスを受け取ります。これにより、クライアントがすべてのWebServiceのすべてのメソッドで認証されているかどうかを確認する必要があります。これは、私がやりたくないものです(クロスカットとDRY違反)。 – Alex

+0

私は、処理チェーンを実装するコードのソースをチェックしたときに、内部的に中断を実行することによってフォールトを処理するために_seems_するので尋ねました。しかし、コードは100%明確ではありません。 –

答えて

2

提案に続いてDonal Fellows私の質問に答えを加えています。

CXFは、あらゆる種類の問題を引き起こす可能性のあるSpringのAOPに大きく依存しています。私はあなたのための完全なコードを提供しています。オープンソースプロジェクトを使用すると、WS-Securityを使用しない(私のサービスがSSL上でのみ実行されることを期待している)人には、ほんの数行のコードを提供することが公正だと思います。私はCXFのソースを閲覧することでそのほとんどを書いていました。

もっと良いアプローチがあると思いますか、ご意見ください。

/** 
* Checks the requested action for AuthenticationRequired annotation and tries 
* to login using SOAP headers username/password. 
* 
* @author Alexander Hofbauer 
*/ 
public class AuthInterceptor extends AbstractSoapInterceptor { 
    public static final String KEY_USER = "UserAuth"; 

    @Resource 
    UserService userService; 

    public AuthInterceptor() { 
     // process after unmarshalling, so that method and header info are there 
     super(Phase.PRE_LOGICAL); 
    } 

    @Override 
    public void handleMessage(SoapMessage message) throws Fault { 
     Logger.getLogger(AuthInterceptor.class).trace("Intercepting service call"); 

     Exchange exchange = message.getExchange(); 
     BindingOperationInfo bop = exchange.getBindingOperationInfo(); 
     Method action = ((MethodDispatcher) exchange.get(Service.class) 
       .get(MethodDispatcher.class.getName())).getMethod(bop); 

     if (action.isAnnotationPresent(AuthenticationRequired.class) 
       && !authenticate(message)) { 
      Fault fault = new Fault(new Exception("Authentication failed")); 
      fault.setFaultCode(new QName("Client")); 

      try { 
       Document doc = DocumentBuilderFactory.newInstance() 
         .newDocumentBuilder().newDocument(); 
       Element detail = doc.createElementNS(Soap12.SOAP_NAMESPACE, "test"); 
       detail.setTextContent("Failed to authenticate.\n" + 
         "Please make sure to send correct SOAP headers username and password"); 
       fault.setDetail(detail); 

      } catch (ParserConfigurationException e) { 
      } 

      throw fault; 
     } 
    } 

    private boolean authenticate(SoapMessage msg) { 
     Element usernameNode = null; 
     Element passwordNode = null; 

     for (Header header : msg.getHeaders()) { 
      if (header.getName().getLocalPart().equals("username")) { 
       usernameNode = (Element) header.getObject(); 
      } else if (header.getName().getLocalPart().equals("password")) { 
       passwordNode = (Element) header.getObject(); 
      } 
     } 

     if (usernameNode == null || passwordNode == null) { 
      return false; 
     } 
     String username = usernameNode.getChildNodes().item(0).getNodeValue(); 
     String password = passwordNode.getChildNodes().item(0).getNodeValue(); 

     User user = null; 
     try { 
      user = userService.loginUser(username, password); 
     } catch (BusinessException e) { 
      return false; 
     } 
     if (user == null) { 
      return false; 
     } 

     msg.put(KEY_USER, user); 
     return true; 
    } 
} 

上記のように、ここにExceptionHandler/-Loggerがあります。最初はJAX-RSと組み合わせて使用​​できませんでした(CXF経由でもJAX-WSはうまく動作します)。とにかくJAX-RSは必要ないので、今問題は解消されました。

@Aspect 
public class ExceptionHandler { 
    @Resource 
    private Map<String, Boolean> registeredExceptions; 


    /** 
    * Everything in my project. 
    */ 
    @Pointcut("within(org.myproject..*)") 
    void inScope() { 
    } 

    /** 
    * Every single method. 
    */ 
    @Pointcut("execution(* *(..))") 
    void anyOperation() { 
    } 

    /** 
    * Log every Throwable. 
    * 
    * @param t 
    */ 
    @AfterThrowing(pointcut = "inScope() && anyOperation()", throwing = "t") 
    public void afterThrowing(Throwable t) { 
     StackTraceElement[] trace = t.getStackTrace(); 
     Logger logger = Logger.getLogger(ExceptionHandler.class); 

     String info; 
     if (trace.length > 0) { 
      info = trace[0].getClassName() + ":" + trace[0].getLineNumber() 
        + " threw " + t.getClass().getName(); 
     } else { 
      info = "Caught throwable with empty stack trace"; 
     } 
     logger.warn(info + "\n" + t.getMessage()); 
     logger.debug("Stacktrace", t); 
    } 

    /** 
    * Handles all exceptions according to config file. 
    * Unknown exceptions are always thrown, registered exceptions only if they 
    * are set to true in config file. 
    * 
    * @param pjp 
    * @throws Throwable 
    */ 
    @Around("inScope() && anyOperation()") 
    public Object handleThrowing(ProceedingJoinPoint pjp) throws Throwable { 
     try { 
      Object ret = pjp.proceed(); 
      return ret; 
     } catch (Throwable t) { 
      // We don't care about unchecked Exceptions 
      if (!(t instanceof Exception)) { 
       return null; 
      } 

      Boolean throwIt = registeredExceptions.get(t.getClass().getName()); 
      if (throwIt == null || throwIt) { 
       throw t; 
      } 
     } 
     return null; 
    } 
} 
1

短い答え、要求を送信する前に、クライアント側のインターセプタで中止する正しい方法は、ラップされた例外に障害を作成することです:考え出す助けるための貢献を投稿する

throw new Fault(
     new ClientException(// or any non-Fault exception, else blocks in 
     // abstractClient.checkClientException() (waits for missing response code) 
     "Error before sending the request"), Fault.FAULT_CODE_CLIENT); 

感謝それを出す。

1

CXFでは、インターセプタが特定のインターセプタの前後に移動するように指定できます。インターセプタがインバウンド側で処理している場合(説明に基づき)、CheckFaultInterceptorというインターセプタがあります。あなたはそれの前に行くために、あなたのインターセプタを設定することができます。

public HeadersInterceptor(){ 
    super(Phase.PRE_LOGICAL); 
    getBefore().add(CheckFaultInterceptor.class.getName()); 
} 

チェック障害インターセプタを理論チェックで障害が発生した場合。存在する場合、インターセプタチェーンをアボートし、フォールトハンドラチェーンを呼び出します。

あなただけの障害を投げるとCXFを処理させることができない私はまだ(それは完全に私が関連する問題を解決しようとして渡って来て利用できるドキュメントに基づいています)これをテストすることができていない

+0

また、追加点として、使用する前にフェーズで障害を発生させるインターセプタを置くことは悪い考えです。フォルトに必要なフィールドが設定されず、 CXF障害処理の例外。私はCXFバージョン2.4.3で問題を抱えていましたが、パイプストリームを閉じることに関して適切に処理されない例外がありました。アプリケーションが無期限にハングする原因となりました(具体的には2.7.6と2.7.7で遭遇しましたNPEはまだ2.4.3で正常に戻った)。 – romeara

関連する問題