簡體   English   中英

在Apache CXF Interceptor中編寫消息內容和響應代碼

[英]Write message content and response code in Apache CXF Interceptor

我試圖通過使其中一個方法需要HTTP基本身份驗證來確保我的Web服務安全。 為了做到這一點,我實現了一個名為LoginInterceptor的自定義攔截器來檢查請求的URL,如果它對應於一個名為open的方法,它會檢查郵件頭是否LoginInterceptor戶名和密碼。

如果標頭中沒有驗證字段,則響應代碼設置為HTTP_UNAUTHORIZED ,如果用戶名或密碼不正確,則響應代碼將設置為HTTP_FORBIDDEN 這是代碼:

public LoginInterceptor() {
     super(Phase.RECEIVE);
     addAfter(RequestInterceptor.class.getName()); //another custom interceptor, for some simple redirections.
}

public void handleMessage(Message message) throws Fault {
     String requestURI = message.get(Message.REQUEST_URI).toString();
     String methodKeyword = requestURI.substring("localhost".length()+1).split("/")[0];

     if(methodKeyword.equals("open")) {
          AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);
          if(policy == null) {
              sendErrorResponse(message, HttpURLConnection.HTTP_UNAUTHORIZED);
              return;
          }

          //userPasswords is a hashmap of usernames and passwords.     
          String realPassword = userPasswords.get(policy.getUserName());
          if (realPassword == null || !realPassword.equals(policy.getPassword())) {
                    sendErrorResponse(message, HttpURLConnection.HTTP_FORBIDDEN);
          }
     }
}

//This is where the response code is set, and this is where I'd like to write the response message.
private void sendErrorResponse(Message message, int responseCode) {
    Message outMessage = getOutMessage(message);
    outMessage.put(Message.RESPONSE_CODE, responseCode);

    // Set the response headers
    Map responseHeaders = (Map) message.get(Message.PROTOCOL_HEADERS);

    if (responseHeaders != null) {
        responseHeaders.put("Content-Type", Arrays.asList("text/html"));
        responseHeaders.put("Content-Length", Arrays.asList(String.valueOf("0")));
    }

    message.getInterceptorChain().abort();

    try {
        getConduit(message).prepare(outMessage);
        close(outMessage);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private Message getOutMessage(Message inMessage) {
    Exchange exchange = inMessage.getExchange();
    Message outMessage = exchange.getOutMessage();

    if (outMessage == null) {
            Endpoint endpoint = exchange.get(Endpoint.class);
            outMessage = endpoint.getBinding().createMessage();
            exchange.setOutMessage(outMessage);
    }

    outMessage.putAll(inMessage);

    return outMessage;

}

//Not actually sure what this does. Copied from a tutorial online. Any explanation is welcome
private Conduit getConduit(Message inMessage) throws IOException {
    Exchange exchange = inMessage.getExchange();
    Conduit conduit = exchange.getDestination().getBackChannel(inMessage);
    exchange.setConduit(conduit);
    return conduit;
}

private void close(Message outMessage) throws IOException {
    OutputStream os = outMessage.getContent(OutputStream.class);
    os.flush();
    os.close();
}

這工作正常,但是,我想在響應中返回一條消息,例如“用戶名或密碼不正確”。 我已嘗試從sendErrorResponse方法中執行以下操作:

outMessage.setContent(String.class, "incorrect username or password") ,我將content-length設置為"incorrect username or password".length() 這不起作用,我猜是因為Apache CXF消息使用InputStreamOutputStream

所以我嘗試過:

OutputStream os = outMessage.getContent(OutputStream.class);
try {
    os.write("incorrect username or password".getBytes() );
    outMessage.setContent(OutputStream.class, os);
 } catch (IOException e) {
    e.printStackTrace();
 }

這也不起作用。 當使用調試器單步執行時,我注意到osnull當使用Postman進行測試時,我得到:

無法獲得任何響應這似乎是連接到http://localhost:9090/launcher/open 響應狀態為0.有關何時發生此更多詳細信息,請查看W3C XMLHttpRequest Level 2規范。

在Chrome中按ctrl + shif + c(打開開發工具),然后檢查網絡標簽,我看到:

"ERR_CONTENT_LENGTH_MISMATCH"

我已經嘗試過使用XMLStreamWriter,但是沒有更好的。

問題:

  • 我可以返回正確的響應代碼(401 Unauthorized和403 forbidden),但是如何在響應正文中返回消息?

  • 我是否需要專門擴展特定的OutInterceptor,如JASRXOutInterceptor才能修改消息內容?

  • 我之前嘗試過使用JAASInterceptor,但我沒有設法讓它工作。 有人可以告訴我如何以這種方式實現它,如果這在某種程度上更容易嗎?

  • 我也可以像這樣拋出一個錯誤: throw new Fault("incorrect username or password", Logger.getGlobal()); ,但是HTTP響應代碼將是500.我寧願返回正確的401或403響應。

注意:

現在我仍在使用HTTP作為傳輸層。 解決這個問題后,我將更改為HTTPS。

基本上,我想要做的是返回錯誤,HTTP響應代碼為401(未授權)或403(禁止)而不是500(服務器錯誤)。 事實證明Apache CXF提供了一種簡單的方法,使用Fault.setStatusCode(int) method ,正如我在Stack Overflow上的這個問題中發現的: 如何在Apache CXF中拋出403錯誤 - Java

所以這就是我的handleMessage方法現在的樣子:

public void handleMessage(Message message) throws Fault {
        String requestURI = message.get(Message.REQUEST_URI).toString();
        String methodKeyword = requestURI.substring("localhost".length()+1).split("/")[0];

        if(methodKeyword.equals("open")) {
            AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);

            if(policy == null) {
                Fault fault = new Fault("incorrect username or password", Logger.getGlobal());
                fault.setStatusCode(401);
                throw fault;
            }

            String realPassword = userPasswords.get(policy.getUserName());
            if (realPassword == null || !realPassword.equals(policy.getPassword())) {
                Fault fault = new Fault("incorrect username or password", Logger.getGlobal());
                fault.setStatusCode(403);
                throw fault;
            }
        }
    }

我刪除了其他方法,它們是不必要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM