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

时间:2012-03-13 00:05:08

标签: java maven jersey

我有以下情况:

服务器:Jetty(已配置JAAS)

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

我在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);
}

请注意:

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

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

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

我似乎错过了什么?

5 个答案:

答案 0 :(得分:22)

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

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

要使基于表单的身份验证起作用,您必须发送包含用户名和密码的表单数据的帖子请求才能登录,然后将您从服务器收到的Cookie设置为后续请求(因为服务器 - 一旦你登录 - 将设置会话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);

我没有测试过这个,所以可能会有一些拼写错误或错误。

答案 1 :(得分:10)

我不使用泽西岛,但这本身并不是泽西岛问题
首先,您必须使用FORM登录或BASIC身份验证;除非这是一个自定义开发,否则我怀疑你使用的是“具有基本身份验证的表单”。

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

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

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

< / p>

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

How to get jersey logs at server?

答案 2 :(得分:3)

JAAS的授权:

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

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

    client.addFilter(new HTTPBasicAuthFilter(username, password));

    // Get the protected web page:
    WebResource webResource = client.resource(URL_DATA);
    String response = webResource.get(String.class);
    System.out.println(response);

答案 3 :(得分:2)

要通过基于表单的身份验证访问其余端点,需要在JAX-RS Jersey客户端中注册一个表单身份验证过滤器。以下git hub链接提供了一种有用的过滤器类。

https://github.com/imixs/imixs-melman/blob/master/src/main/java/org/imixs/melman/FormAuthenticator.java

在您的项目和Rest Jersey客户端中使用FormAuthenticator.java进行以下操作:

// Constructor of jersey Rest client
public RestClass(String username, String password)
{
    private WebTarget webTarget;
    private Client client;

    private static final String BASE_URI = "http://localhost:8080/SampleRest/webresources";

    client = javax.ws.rs.client.ClientBuilder.newClient();
    client.register(new FormAuthenticator(BASE_URI, user,  password));

    webTarget = client.target(BASE_URI).path("restpath");
}

一切正常。我用过了,这个问题解决了。 JAX-RS API必须在其发行版中提供此身份验证器。

注意:在基于表单的身份验证中使用的用户名和密码将由Servlet中的调用客户端提供。

as RestClient rs = new RestClient(username, password);

**复制类应注册RolesAllowedDynamicFeature才能使角色生效** Rest类和FormAuthenticator.java驻留在REST包中的Web Project中的MyApplication.java

@ApplicationPath("webresources")

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        packages("entity.service");
        packages("rest");
        register(RolesAllowedDynamicFeature.class);
    }
}

答案 4 :(得分:1)

对我来说,这些变化解决了这个问题:

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";


// Get the protected web page: (this will make the server know that someone will try to access the protected resource)
WebResource  webResource = client.resource(URL_DATA);
String response = webResource.get(String.class);


// Login:
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: (this time the service will return the data)
webResource = client.resource(URL_DATA);
response = webResource.get(String.class);