2011-05-27 33 views
17

我有一個Java Web應用程序,它具有用於用戶交互的網站。爲了驗證用戶,我通過web.xml配置了應用程序以使用基於FORM的身份驗證。用戶被轉發到登錄頁面,目前一切都很好。用於Java webapp的多個登錄配置

現在我們正在爲此Web應用程序開發一個桌面客戶端(使用C#),它通過RESTful Web服務訪問應用程序。我在與網站相同的Web應用程序中實現了這些服務,當然,Web服務的調用者也應該進行身份驗證。但是現在我面臨這個問題,每當我調用一個Web服務時,服務器都會返回登錄頁面的HTML作爲響應。

我認爲能夠爲我的REST服務Servlet使用另一個登錄配置將很酷(可能會使用BASIC身份驗證)。

谷歌沒有提高,但我不敢相信我是第一個在這種情況下。所以我想聽聽你的想法和解決方案。

任何提示表示讚賞。

回答

5

唯一的解決方案是爲兩個具有不同登錄機制的客戶端提供兩個應用程序。應用程序代碼應該被分離,並將它轉移到通用應用程序中,以便這些應用程序轉發請求。

否則,使用您的自定義驗證。

+0

謝謝。我已經認爲這是不可能的。所以我認爲最好的選擇是爲web服務實現自定義身份驗證... – hage 2011-05-27 10:51:03

1

不幸的是,login-config沒有像過濾器那樣映射,servlet只有一個全局的webapp。這意味着你要麼需要2個Web應用程序,要麼在JBoss上,你可以使用WebAuthentication類來通知容器你的應用程序的編程登錄。但是,如果您正在使用嵌入式jetty或其他Web服務器,則絕對沒有辦法使用web.xml一起支持BASIC和FORM。您將不得不編寫自定義身份驗證服務

但是,您可以轉換爲Apache Shiro,並且它可以用寫得非常好的簡單設計來解決這些問題。這些步驟將允許REST客戶端在沒有會話cookie的每個頁面上使用BASIC身份驗證,或者在/ rest/login上登錄並接收會話。然後瀏覽器客戶端可以使用FORM auth

1) protect /login with "authc", set shiro.loginUrl to /login and host an HTML form at that location 
2) protect /rest/login with "anon" and write a URL handler for POST with this code 
    UsernamePasswordToken token = new UsernamePasswordToken(userName, password); 
    token.setRememberMe(rememberMe); 
    SecurityUtils.getSubject().login(token); 
3) protect /rest/logout with "logout" 
4) protect /rest/** with "noSessionCreation, authcBasic, rest" 
3

我已經用tomcat閥門解決了這個問題。閥檢查是否存在授權標頭,在這種情況下,標頭用作認證用戶的憑證,否則將發生正常的認證方法。

這裏是閥門的代碼:

package org.tastefuljava.tomcat; 

import java.io.IOException; 
import java.security.Principal; 
import javax.servlet.ServletException; 
import org.apache.catalina.Realm; 
import org.apache.catalina.connector.Request; 
import org.apache.catalina.connector.Response; 
import org.apache.catalina.valves.ValveBase; 

public class AutoBasicValve extends ValveBase { 
    private static final String BASIC_PREFIX = "basic "; 

    private String encoding = "UTF-8"; 

    public String getEncoding() { 
     return encoding; 
    } 

    public void setEncoding(String encoding) { 
     this.encoding = encoding; 
    } 

    @Override 
    public void invoke(Request request, Response response) 
      throws IOException, ServletException { 
     Principal principal = request.getUserPrincipal(); 
     Realm realm = getContainer().getRealm(); 
     if (principal != null) { 
      if (containerLog.isDebugEnabled()) { 
       containerLog.debug(
         "Already authenticated as: " + principal.getName()); 
      } 
     } else if (realm == null) { 
      if (containerLog.isDebugEnabled()) { 
       containerLog.debug("No realm configured"); 
      } 
     } else { 
      String auth = request.getHeader("authorization"); 
      if (auth != null) { 
       if (auth.toLowerCase().startsWith(BASIC_PREFIX)) { 
        auth = auth.substring(BASIC_PREFIX.length()); 
        byte[] bytes = Base64.decode(auth); 
        auth = new String(bytes, encoding); 
        int ix = auth.indexOf(':'); 
        if (ix >= 0) { 
         String username = auth.substring(0, ix); 
         String password = auth.substring(ix+1); 
         principal = realm.authenticate(username, password); 
         if (principal == null) { 
          containerLog.warn(
            "Could not authenticate " + username); 
         } else { 
          containerLog.info(
            "Authenticated as " + principal.getName()); 
          request.setAuthType("BASIC"); 
          request.setUserPrincipal(principal); 
         } 
        } 
       } 
      } 
     } 
     getNext().invoke(request, response); 
    } 
} 

您可以通過在你的tomcat安裝在server.xml文件中添加<閥門>標籤使用的閥門,或在META-INF /上下文。您Web應用程序的XML文件:

該項目在GitHub上:https://github.com/robbyn/mydsrealm

+0

哇,很酷。如果它仍然是2011年,我可以使用它:)但感謝您的工作!我希望它能幫助別人。 現在,如果Glassfish有類似的事情嗎? – hage 2015-11-11 13:52:46

+0

對不起,我不知道 – 2015-11-11 19:28:00