2013-02-26 41 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