实施春季安全与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();
(我不能改变该代码,只有我可以改变的事情是在调用方法时将urlStr
和data
发送到服务器)。
[编辑]:客户端可以是Java客户端或任何其他客户端(C++,objective-c,..)。这里的要点是,我只能访问我的帖子正文以及网址。
服务器端
在我的服务器端,我想实现的Spring Security(SecurityContext中和会话持久性)。
据我所知,弹簧安全是基于浏览器的cookies,当它是一个WebApp
来保存有关session id
的信息。但在我的情况下,没有浏览器。
我需要模拟
JSESSIONID
的存储和发送回服务器?我不确定这是可能的,因为我需要拨打conn.addRequestProperty(key, value)
这是不可能的。还有别的办法吗?
谢谢。
[编辑]
由@zagyi指出的那样,我就可以使用URL会话令牌传递到春天,但我仍然无法弄清楚如何。
传递的JSESSIONID在url只是在这样的URL的末尾追加它的事:
http://localhost:8080/example/auth/login;jsessionid=A06F00609BBA8A4C2B005FB25F90C4C9
您可以在工作,如果您配置的浏览器不接受任何cookie看到这一点,在这种情况下,服务器会自动将该会话ID包含在url中(假定默认的tomcat配置)。本主题也在this question中讨论。
是的,我刚刚几个小时才找到这个解决方案,我发送会话ID回到客户端的响应主体,它将其发送回服务器上的网址。 – 2013-03-03 20:46:46
可能有一个客户端解决方案。
的作用点在这里我们可以交流是在这里:
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.xhttp
(xhttp喜欢你的协议名称),请将我们的MyURLStreamHandler
类重命名为com.example.myprotocol.xhttp.Handler
。这是协议解析器将查找它的固定名称。请注意,此java.protocol.handler.pkgs
属性由安全管理器检查。
非常感谢您的回复..现在我应该提到的原因为什么我不能更改客户端的Java代码是因为它只是其中一个实现(我使用PlayN,它是为不同类型的平台提供接口的多平台库)。所以,如果这与java客户端一起工作,那么我无法为iPhone客户端实现它。 – 2013-03-03 00:27:53
现在我正在寻找一种方法来在URL中传递会话ID .. – 2013-03-03 00:29:00
您必须能够传递一些信息,根据请求在服务器端进行身份验证的信息。如果它不是一个cookie,它可能是一个基本的身份验证标题,但是从您的角度来看,这与Cookie没有多大区别...... – zagyi 2013-02-26 18:45:53
所以您建议我将令牌发送给我的客户端,无论何时它会发送一个对服务器的请求(如JSESSIONID令牌)。但是,如何从服务器端生成这个令牌,以及如何根据存储的会话检查它? – 2013-02-26 18:48:51
Option1将在成功登录后将JSESSIONID存储在客户端上,并将每个请求的表单客户端重新发送到服务器。选项2是客户端在auth头中发送每个请求的凭证,然后不需要进行会话处理。 – zagyi 2013-02-26 18:56:43