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

2022-01-21 00:00:00 java maven jersey

我有以下场景:

服务器:Jetty(配置了 JAAS)

Server: Jetty (with configured JAAS)

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

Client: Jersey invoked via JUnit (via Maven)

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

I have JAAS set up in the web server. I am using the client part as a test.

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

On the server side users are authenticated through a form with Basic authentication handled via JAAS. Obviously, users need to be authenticated before being able to view certain pages.

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

I would like to be able to login via the Jersey before trying to access a secured page. How can this be done? I have checked that you can define a filter, but I'm not quite sure how to use that. And -- once the user is logged in via the form, how can I proceed (from the client-side) to the page I'm actually interested in?

如果有人可以向我展示如何在客户端使用 Jersey 完成此操作,我将不胜感激.

I would really appreciate it, if somebody could show me an example how this is done on the client side with Jersey.

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

I have the following JUnit test case method:

@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 是我应该是的页面看到成功的身份验证.

1) http://localhost:9080/foo/auth.html is the page I am supposed to be seeing upon successful auth.

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

2) I am actually seeing the output of http://localhost:9080/foo/login.html.

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

3) Obviously, through a browser, I can successfully login via the login.html page.

我似乎在这里遗漏了什么?

What do I seem to be missing out here?

推荐答案

使用基本身份验证,您根本不需要进入任何登录页面.如果服务器配置为使用基本身份验证,那么如果您在请求中包含基本身份验证标头,则可以向任何受保护的页面发出请求.Jersey 过滤器可以解决这个问题.因此,如果服务器正在使用基本身份验证,那么您的代码应该可以工作.

With Basic auth you don't need to go to any login page at all. If the server is configured to use Basic auth, then you can make requests to any protected page if you include the basic auth header in your requests. The Jersey filter takes care of that. So, if Basic auth would really be what the server is using, then your code should work.

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

Given it does not work and the way it does not work I am pretty sure the server is configured to use form-based authentication instead of the basic authentication.

要使基于表单的身份验证正常工作,您必须发送一个包含表单数据(包括用户名和密码)的 post 请求才能登录,然后将从服务器接收到的 cookie 设置为您的后续请求(因为服务器 -登录后 - 将设置会话 cookie).

For the form-based authentication to work, you'll have to send a post request with form data including user name and password to log in and then set cookies you receive from the server to your subsequent requests (since the server - once you log in - will set the session cookie).

看看 login.html 的样子——它应该包含一个表单.如果它使用标准的 servlet 表单身份验证,该表单的操作 URL 应该是j_security_check"并且应该有两个表单参数:j_username 和 j_password.如果是这种情况,您可以尝试以下方法:

Look at how the login.html looks like - it should contain a form. If it is using the standard servlet form auth., the action URL of that form should be "j_security_check" and there should be two form parameters: j_username and j_password. If that is the case, you can try something like the following:

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

我还没有测试过,所以可能会有一些错别字或错误.

I haven't tested this, so maybe there will be some typos or bugs.

相关文章