【问题标题】:Implementing Spring Security with Java Client使用 Java 客户端实现 Spring Security
【发布时间】:2013-02-12 08:31:44
【问题描述】:

客户端

我有一个使用基本 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

[EDIT] :客户端可以是 java 客户端或任何其他客户端(c++、objective-c、..)。这里的重点是,我只能访问帖子正文中的内容以及 URL。

服务器端

在我的服务器端,我想实现 Spring Security(SecurityContext 和会话持久性)。

我知道 Spring Security 是基于浏览器的 cookie,当它是一个 WebApp 来保存有关 session id 的信息。但就我而言,没有浏览器。

  • 是否需要模拟JSESSIONID的存储并将其发送回服务器?我不确定这是否可行,因为我需要致电 conn.addRequestProperty(key, value) 这是不可能的。

  • 还有其他办法吗?

谢谢。

[编辑]

正如@zagyi 所指出的,我可以使用 URL 将会话令牌传递给 Spring,但我仍然不知道如何。

【问题讨论】:

  • 您必须能够传递一些信息,根据这些信息请求在服务器端进行身份验证。如果它不是 cookie,它可能是一个基本的 auth 标头,但从您的角度来看,这与 cookie 没有太大区别......
  • 所以你建议我向我的客户端发送一个令牌,每当它向服务器发出请求时都会发送该令牌(如 JSESSIONID 令牌)。但是如何从服务器端生成这个令牌,以及如何根据存储的会话检查它?
  • 选项1是在成功登录后将JSESSIONID存储在客户端上,并在每次请求时将该表单客户端重新发送到服务器。选项 2 是客户端在 auth 标头中为每个请求发送凭据,然后不需要进行会话处理。
  • 感谢您的回复。选项 1:我从哪里获得服务器上的 JSESSIONID,并且拥有 JSESSIONID 如何获得相应的会话?选项 2:对于每个身份验证,我需要检查数据库,因此检查每个请求都会消耗大量资源。
  • 您可以在 url 中从客户端传递会话 id,然后您的 servlet 容器对其进行处理,并使会话可用于您的 webapp。 Spring Security 组件将通过 http 请求对象访问会话。但这都是实现的,只需要正确配置即可。

标签: java spring session spring-security session-cookies


【解决方案1】:

在 url 中传递 jsessionid 只需将其附加到 url 的末尾,如下所示:

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

如果您将浏览器配置为不接受任何 cookie,您可以看到这一点,在这种情况下,服务器会自动在 url 中包含会话 ID(假设默认的 tomcat 配置)。这个话题也在this question讨论。

【讨论】:

  • 是的,我刚刚在几个小时前找到了这个解决方案,我在响应正文中将会话 ID 发送回客户端,然后通过 url 将其发送回服务器。
【解决方案2】:

可能有一个客户端解决方案。

我们可以互动的行动点在这里:

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 属性由安全管理器检查。

【讨论】:

  • 非常感谢您的回复.. 现在我应该提到我无法更改客户端的 java 代码的原因是它只是其中一种实现(我使用的是 PlayN是一个多平台库,为不同类型的平台提供接口)。因此,如果这适用于 java 客户端,那么我无法为 iPhone 客户端实现它。
猜你喜欢
  • 2012-10-22
  • 2013-06-20
  • 1970-01-01
  • 1970-01-01
  • 2013-04-02
  • 2011-08-27
  • 1970-01-01
  • 2018-11-15
  • 1970-01-01
相关资源
最近更新 更多