2013-07-16 57 views
4

我的Web應用程序使用內部Web API(來自瀏覽器的簡單AJAX請求,因爲它是主要客戶端),它最終應該被外部暴露給第三方。由於API必須受到web.xml中的安全限制的保護,因此必須對用戶或客戶端進行身份驗證。目前,實現了自定義表單驗證器,它執行一些額外的檢查和操作,然後將進一步的驗證處理委託給自定義驗證器派生自的類。這個工作真的很好,因爲用戶只是被迫登錄並通過身份驗證,唯一的客戶端是一個Web瀏覽器。Tomcat:單個Web應用程序的多個身份驗證方案?

,而是形成認證不是很適合另一種類型的客戶端:比方說,一個Android客戶端,各種第三方客戶端等太傳遞形式的認證都必須模擬我一直在尋找這個問題的行爲: How can I simulate form authentication in Tomcat using JMeter?。在對Tomcat源代碼進行了一些調查後,我發現應該可以擴展AuthenticatorBase類來實現自己的認證方式(如FormAuthenticatorBasicAuthenticator.java)。我試圖做的是:

public final class SimpleAuthenticator extends AuthenticatorBase { 

    private static final String USERNAME_PARAMETER = "username"; 
    private static final String PASSWORD_PARAMETER = "password"; 

    @Override 
    protected boolean authenticate(Request request, Response response, LoginConfig config) throws IOException { 
     final Principal principal = request.getUserPrincipal(); 
     final String ssoId = (String) request.getNote(REQ_SSOID_NOTE); 
     if (principal != null) { 
      if (ssoId != null) { 
       associate(ssoId, request.getSessionInternal(true)); 
      } 
      return true; 
     } 
     if (ssoId != null && reauthenticateFromSSO(ssoId, request)) { 
      return true; 
     } 
     final String contextPath = request.getContextPath(); 
     final String requestURI = request.getDecodedRequestURI(); 
     final boolean login = requestURI.equals(contextPath + "/authenticate"); 
     if (!login) { 
      response.sendError(SC_FORBIDDEN); 
      return false; 
     } 
     final String username = request.getParameter(USERNAME_PARAMETER); 
     final String password = request.getParameter(PASSWORD_PARAMETER); 
     final Realm realm = context.getRealm(); 
     final Principal authenticatedUserPrincipal = realm.authenticate(username, password); 
     if (authenticatedUserPrincipal == null) { 
      response.sendError(SC_UNAUTHORIZED); 
      return false; 
     } 
     register(request, response, authenticatedUserPrincipal, "SIMPLE", username, password); 
     return true; 
    } 

} 

簡單地說,我想使用類似/%CONTEXT_PATH%/authenticate?username=%USERNAME%&password=%PASSWORD%用戶與我定做非形式SimpleAuthenticator驗證。真的不知道,如果BasicAuthentication將是這樣的情況更好,但我得到了與上面的例子以下問題:

  • 的Tomcat允許指定多個Valve的在context.xml。如果另一個認證者被添加到context.xml文件中,則每個認證者都會處理每個安全資源。 (原則上,我理解它爲什麼會發生,但是它們可以分開用於不同的資源嗎?)
  • /%CONTEXT_PATH%/authenticate不可訪問(HTTP 404)。 (還不清楚/j_security_check是以某種方式模擬的。)
  • 我找不到在Tomcat中指定多個身份驗證方案的方法,因此「舊」web瀏覽器客戶端仍然可以使用FormAuthenticator(就像今天這樣),但是「輕量級」客戶可以使用我試圖用SimpleAuthenticator實現的簡化認證。 (甚至不知道是否有可能 - 這是核心)
  • 據我瞭解servlet規範,整個web應用程序只允許使用一個login-config。 (好吧,我應該使用另一個Web應用程序來提供API嗎?)
  • 我看到一些提到通過Filter實現自定義驗證,但如果可能的話 - 我想將驗證器模塊分開保存在一個地方(就像它已經和Tomcat: Custom form authenicator in a web application, not as a stand-alone JAR module. Possible?確認)。不過,我很好地回顧了我從頭開始使用的一般概念。

我懷疑我做了一件非常錯誤的事情,並且有完全的理解,但我不相信在Tomcat中沒有辦法實現多個身份驗證方案。

有沒有什麼辦法可以提供多種身份驗證方案來從FormAuthetication(輕量級客戶端)中提取身份驗證?您的幫助將非常感激。提前致謝。

+0

這個限制讓我發瘋 –

回答

2

底線:您無法在Tomcat中爲同一個Web應用程序配置多個身份驗證方案。 你配置一個AUTH-方法將用於在web.xml認證:

<login-config> 
    <auth-method>CLIENT-CERT</auth-method> 
</login-config> 

上認證爲Web應用程序的認證Tomcat的地圖。 例如,對於CLIENT-CERT它將使用org.apache.catalina.authenticator.SSLAuthenticator 的映射文件org/apache/catalina/startup/Authenticators.properties

爲目的,在您的問題描述,你可以使用正Tomcat的形式驗證器(<auth-method>FORM</auth-method>

下面的代碼將進行身份驗證用戶:

String url = "j_security_check?j_username=" + username + "&j_password=" + password; 
String redirectUrl = response.encodeRedirectURL(url); 
response.sendRedirect(redirectUrl); 

當你第一次訪問應用程序通過上面的執行URL驗證用戶。 另外,您可以使用Form Authenticator for「old」code :) 請注意,上面的代碼使用GET方法。 我建議將POST方法中的相同參數提交到j_security_check(您可以在AJAX中執行)。

+0

感謝您的回覆,但據我所知,不能像這樣工作,因爲FormAuthenticator需要基於重定向的特殊登錄序列(因此保持重定向之間的狀態)。請參閱http://stackoverflow.com/questions/7246759/how-can-i-simulate-form-authentication-in-tomcat-using-jmeter –

+0

您是否嘗試執行URL?它適用於我的環境。我相信我會幫助你解決你的問題。 – Michael

+0

半年過去了,但我仍然覺得我必須回覆。 :)我對重定向並不完全正確,但真正的問題仍然是:如果客戶端在驗證後嘗試請求安全資源,然後會話失效(例如會話超時後),則會轉發資源請求到登錄頁面,無論受保護資源的類型是什麼(您請求JSON,並且您獲得了HTML登錄頁面 - 這是FormAuthenticator帶來的)。我可以依賴HTTP狀態碼(我可以嗎?),但發送登錄頁面過度並且有點可怕 –

相關問題