2013-02-26 44 views
2

客戶端實施春季安全與Java客戶端

我有一個使用基本POST或GET方法連接到遠程服務器的Java應用程序:

URL url = new URL(urlStr); 
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
conn.setRequestMethod("POST"); 
conn.setDoOutput(true); 
conn.setDoInput(true); 
conn.setAllowUserInteraction(false); 
conn.setRequestProperty("Content-type", "text/xml; charset=" + ENCODING); 

conn.connect(); 
conn.getOutputStream().write(data.getBytes(ENCODING)); 
conn.getOutputStream().close(); 

(我不能改變該代碼,只有我可以改變的事情是在調用方法時將urlStrdata發送到服務器)。

[編輯]:客戶端可以是Java客戶端或任何其他客戶端(C++,objective-c,..)。這裏的要點是,我只能訪問我的帖子正文以及網址。

服務器端

在我的服務器端,我想實現的Spring Security(SecurityContext中和會話持久性)。

據我所知,彈簧安全是基於瀏覽器的cookies,當它是一個WebApp來保存有關session id的信息。但在我的情況下,沒有瀏覽器。

  • 我需要模擬JSESSIONID的存儲和發送回服務器?我不確定這是可能的,因爲我需要撥打conn.addRequestProperty(key, value)這是不可能的。

  • 還有別的辦法嗎?

謝謝。

[編輯]

由@zagyi指出的那樣,我就可以使用URL會話令牌傳遞到春天,但我仍然無法弄清楚如何。

+0

您必須能夠傳遞一些信息,根據請求在服務器端進行身份驗證的信息。如果它不是一個cookie,它可能是一個基本的身份驗證標題,但是從您的角度來看,這與Cookie沒有多大區別...... – zagyi 2013-02-26 18:45:53

+0

所以您建議我將令牌發送給我的客戶端,無論何時它會發送一個對服務器的請求(如JSESSIONID令牌)。但是,如何從服務器端生成這個令牌,以及如何根據存儲的會話檢查它? – 2013-02-26 18:48:51

+0

Option1將在成功登錄後將JSESSIONID存儲在客戶端上,並將每個請求的表單客戶端重新發送到服務器。選項2是客戶端在auth頭中發送每個請求的憑證,然後不需要進行會話處理。 – zagyi 2013-02-26 18:56:43

回答

2

傳遞的JSESSIONID在url只是在這樣的URL的末尾追加它的事:

http://localhost:8080/example/auth/login;jsessionid=A06F00609BBA8A4C2B005FB25F90C4C9 

您可以在工作,如果您配置的瀏覽器不接受任何cookie看到這一點,在這種情況下,服務器會自動將該會話ID包含在url中(假定默認的tomcat配置)。本主題也在this question中討論。

+0

是的,我剛剛幾個小時才找到這個解決方案,我發送會話ID回到客戶端的響應主體,它將其發送回服務器上的網址。 – 2013-03-03 20:46:46

1

可能有一個客戶端解決方案。

的作用點在這裏我們可以交流是在這裏:

HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 

我們將提供自己的(包裹)HttpURLConnection,它將處理JSESSIONID。但不幸的是,我們必須進一步開始。

訣竅是我們註冊一個新的協議,例如, 「xhttp」,我們用它來包裝一個真正的「http」協議連接。所以,你的URL看起來像:

xhttp://www.example.com/... 

首先,定義一個URLStreamHandlerFactory

public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory { 
    public URLStreamHandler createURLStreamHandler(String protocol) { 
     if ("xhttp".equals(protocol)) { 
      return new MyURLStreamHandler(); 
     } 
     return null; 
    } 
} 

在Java(或應用程序)初始化時,我們可以設置它。每個JVM只能執行一次。

URLStreamHandlerFactory fac = new MyURLStreamHandlerFactory(); 
URL.setURLStreamHandlerFactory(fac); 

因此,我們繼續使用MyURLStreamHandler

public class MyURLStreamHandler extends URLStreamHandler { 
    @Override 
    protected URLConnection openConnection(URL url) throws IOException { 
     return new MyHttpURLConnection(url); 
    } 
} 

這很簡單,我們創建自己的連接。讓我們做的髒東西:

public final class MyHttpURLConnection extends HttpURLConnection { 
    private HttpURLConnection conn; 
    public MyHttpURLConnection(URL url) throws MalformedURLException, IOException { 
     super(url); 
     String newUrlString = url.toExternalForm().substring(1); 
     conn = (HttpURLConnection) new URL(newUrlString).openConnection(); 
    } 
    @Override 
    public void disconnect() { 
     conn.disconnect(); 
    } 
    @Override 
    public boolean usingProxy() { 
     return false; 
    } 
    @Override 
    public void connect() throws IOException { 
     conn.connect(); 
     conn.setRequestProperty("JSESSIONID", "X"); 
    } 
} 

,瞧,我們成功地訪問我們的連接,並設置JSESSIONID頭。

您所需要的只是編譯您的類,將類文件添加到客戶端jar中,並使init代碼在上述代碼運行的相同JVM中以某種方式運行。

如果你不能做到這一點,還有另外一種可能:設置以下系統參數給客戶端的Java應用程序:

-Djava.protocol.handler.pkgs=com.example.myprotocol 

在這種情況下創建一個com.example.myprotocol.xhttpxhttp喜歡你的協議名稱),請將我們的MyURLStreamHandler類重命名爲com.example.myprotocol.xhttp.Handler。這是協議解析器將查找它的固定名稱。請注意,此java.protocol.handler.pkgs屬性由安全管理器檢查。

+0

非常感謝您的回覆..現在我應該提到的原因爲什麼我不能更改客戶端的Java代碼是因爲它只是其中一個實現(我使用PlayN,它是爲不同類型的平臺提供接口的多平臺庫)。所以,如果這與java客戶端一起工作,那麼我無法爲iPhone客戶端實現它。 – 2013-03-03 00:27:53

+0

現在我正在尋找一種方法來在URL中傳遞會話ID .. – 2013-03-03 00:29:00