如何使用Jersey Client对启用了JAAS的Web服务器进行身份验证?

car*_*ing 11 java jersey maven

我有以下场景:

服务器:Jetty(配置JAAS)

客户端:通过JUnit调用Jersey(通过Maven)

我在Web服务器中设置了JAAS.我使用客户端部分作为测试.

在服务器端,用户通过具有通过JAAS处理的基本身份验证的表单进行身份验证.显然,用户需要在能够查看某些页面之前进行身份验证.

我想在尝试访问安全页面之前能够通过Jersey登录.如何才能做到这一点?我已经检查过你可以定义一个过滤器,但我不太清楚如何使用它.并且 - 一旦用户通过表单登录,我该如何进行(从客户端)到我真正感兴趣的页面?

我真的很感激,如果有人能告诉我一个例子如何在泽西岛的客户端做到这一点.

我有以下JUnit测试用例方法:

@Test
public void testLogin()
        throws IOException
{
    String URL_LOGIN = "http://localhost:9080/foo/auth.html";
    Client client = Client.create();

    String username = "me";
    String password = "me";

    final HTTPBasicAuthFilter authFilter = new HTTPBasicAuthFilter(username, password);
    client.addFilter(authFilter);
    client.addFilter(new LoggingFilter());

    WebResource webResource = client.resource(URL_LOGIN);
    // I even tried:
    // webResource.header("Authorization", "Basic " + "base64encoded_userid:password").type("application/xml");

    String page = webResource.post(String.class);

    System.out.println(page);
}
Run Code Online (Sandbox Code Playgroud)

请注意:

1)http:// localhost:9080/foo/auth.html是我应该在成功验证后看到的页面.

2)我实际上看到了http:// localhost:9080/foo/login.html的输出.

3)显然,通过浏览器,我可以通过login.html页面成功登录.

我似乎错过了什么?

Mar*_*ula 22

使用Basic auth,您根本不需要访问任何登录页面.如果服务器配置为使用Basic auth,那么如果在请求中包含基本auth标头,则可以向任何受保护页面发出请求.泽西过滤器负责这一点.因此,如果Basic auth确实是服务器正在使用的,那么您的代码应该可以工作.

鉴于它不起作用以及它不起作用的方式我很确定服务器配置为使用基于表单的身份验证而不是基本身份验证.

要使基于表单的身份验证起作用,您必须发送包含用户名和密码的表单数据的帖子请求以登录,然后将从服务器收到的cookie设置为后续请求(因为服务器 - 一旦您登录in - 将设置会话cookie).

看看login.html的样子 - 它应该包含一个表单.如果它使用标准的servlet格式auth.,那个表单的操作URL应该是"j_security_check",并且应该有两个表单参数:j_username和j_password.如果是这种情况,您可以尝试以下内容:

String URL_LOGIN = "http://localhost:9080/foo/j_security_check";
String URL_DATA = "http://localhost:9080/foo/auth.html";
Client client = Client.create();

// add a filter to set cookies received from the server and to check if login has been triggered
client.addFilter(new ClientFilter() {
    private ArrayList<Object> cookies;

    @Override
    public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
        if (cookies != null) {
            request.getHeaders().put("Cookie", cookies);
        }
        ClientResponse response = getNext().handle(request);
        // copy cookies
        if (response.getCookies() != null) {
            if (cookies == null) {
                cookies = new ArrayList<Object>();
            }
            // A simple addAll just for illustration (should probably check for duplicates and expired cookies)
            cookies.addAll(response.getCookies());
        }
        return response;
    }
});

String username = "me";
String password = "me";

// Login:
WebResource webResource = client.resource(URL_LOGIN);

com.sun.jersey.api.representation.Form form = new Form();
form.putSingle("j_username", username);
form.putSingle("j_password", password);
webResource.type("application/x-www-form-urlencoded").post(form);

// Get the protected web page:
webResource = client.resource(URL_DATA);
String response = webResource.get(String.class);
Run Code Online (Sandbox Code Playgroud)

我没有测试过这个,所以也许会有一些拼写错误或错误.

  • Jersey 1.x的解决方案很好但是泽西2.x呢? (2认同)

Bru*_*der 10

我不使用泽西岛,但这本身并不是泽西岛问题.

首先,您必须使用FORM登录或BASIC身份验证; 除非这是一个自定义开发,我怀疑你使用的是"具有基本身份验证的表单".

如果您使用的是基本身份验证,那么事情非常简单(虽然效率低下):BASIC身份验证是无状态的,您必须在每个请求上发送Authorization:Basic xxxx HTTP头.

如果您正在使用FORM登录,那么事情会更复杂一些.在每个请求中,您应该发送会话ID(存储在Cookie中或使用URL重写).如果您没有发送一个,或者关联的会话无效(因为它已过期),服务器将发送302(重定向)和登录表单.然后,您应该使用用户名和密码作为参数对表单中指示的URL执行FORM POST.如果身份验证成功,则服务器将响应发送到原始请求(以及新的会话ID).因此,在这种情况下,程序化请求必须能够

  • 1.处理cookie(除非你强制URL重写,这是不可能的)
  • 2.检测他们何时获得302并返回请求的登录表格,并在继续之前填写所需的表格帖子.
对于任何HTTP调用(AJAX,REST等)都是如此,请注意,您的服务器使用JAAS或其他身份验证和授权机制这一事实无关紧要:这是一个会话管理问题.

或者,可以通过截取呼叫来获得针对泽西岛的特定解决方案,此处:

如何在服务器上获取泽西日志?