Java 您如何使用 Jersey 客户端对启用了 JAAS 的 Web 服务器进行身份验证?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9676588/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can you authenticate using the Jersey Client against a JAAS enabled web-server?
提问by carlspring
I have the following scenario:
我有以下场景:
Server: Jetty (with configured JAAS)
服务器:Jetty(配置了JAAS)
Client: Jersey invoked via JUnit (via Maven)
客户端:通过 JUnit 调用 Jersey(通过 Maven)
I have JAAS set up in the web server. I am using the client part as a test.
我在 Web 服务器中设置了 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.
在服务器端,用户通过一个表单进行身份验证,基本身份验证通过 JAAS 处理。显然,用户需要经过身份验证才能查看某些页面。
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.
如果有人可以向我展示如何在 Jersey 的客户端上完成此操作的示例,我将不胜感激。
I have the following JUnit test case method:
我有以下 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);
}
Please, note:
请注意:
1) http://localhost:9080/foo/auth.htmlis the page I am supposed to be seeing upon successful auth.
1) http://localhost:9080/foo/auth.html是我应该在成功验证后看到的页面。
2) I am actually seeing the output of http://localhost:9080/foo/login.html.
2)我实际上看到了http://localhost:9080/foo/login.html 的输出。
3) Obviously, through a browser, I can successfully login via the login.html page.
3)显然,通过浏览器,我可以通过login.html页面成功登录。
What do I seem to be missing out here?
我似乎在这里错过了什么?
采纳答案by Martin Matula
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.
使用基本身份验证,您根本不需要转到任何登录页面。如果服务器配置为使用基本身份验证,那么如果您在请求中包含基本身份验证标头,则您可以向任何受保护的页面发出请求。Jersey 过滤器会处理这个问题。因此,如果基本身份验证真的是服务器正在使用的,那么您的代码应该可以工作。
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.
鉴于它不起作用以及它不起作用的方式,我很确定服务器配置为使用基于表单的身份验证而不是基本身份验证。
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).
要使基于表单的身份验证工作,您必须发送包含表单数据(包括用户名和密码)的 post 请求以登录,然后将从服务器接收的 cookie 设置为后续请求(因为服务器 - 一旦您登录in - 将设置会话cookie)。
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:
看看 login.html 的样子——它应该包含一个表单。如果它使用标准的 servlet 表单身份验证,那么该表单的操作 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);
I haven't tested this, so maybe there will be some typos or bugs.
我还没有测试过这个,所以也许会有一些错别字或错误。
回答by Bruno Grieder
I do not use Jersey but this is not a Jersey issue per se.
First, you must be using either FORM login or BASIC authentication; unless this is a custom development I doubt you are using a 'Form with Basic Authentication'.
我不使用泽西岛,但这本身不是泽西岛的问题。
首先,您必须使用 FORM 登录或 BASIC 身份验证;除非这是自定义开发,否则我怀疑您使用的是“具有基本身份验证的表单”。
If you are using Basic Authentication, then things are pretty simple (though inefficient): BASIC authentication is stateless and you must send the Authorization: Basic xxxxHTTP header on EVERY request.
如果您使用的是基本身份验证,那么事情非常简单(尽管效率低下):基本身份验证是无状态的,您必须在每个请求上发送Authorization: Basic xxxxHTTP 标头。
If you are using FORM login, things a re a bit more involved. On every request, you are supposed to send the Session Id (stored in a Cookie or using URL rewriting). If you do not send one, or if the associated session is invalidated (because it is expired for instance), the server will send a 302 (redirect) and the Login Form. You are then supposed to perform a FORM POST to the URL indicated in the form with the username and password as parameters. If authentication is successful, the server will then send the response to the original request (and a new session id). In this scenario, programmatic request must therefore be able to
如果您使用 FORM 登录,事情就有点复杂了。对于每个请求,您都应该发送会话 ID(存储在 Cookie 中或使用 URL 重写)。如果您不发送,或者关联的会话无效(例如因为它已过期),服务器将发送 302(重定向)和登录表单。然后,您应该使用用户名和密码作为参数对表单中指示的 URL 执行 FORM POST。如果身份验证成功,服务器将发送对原始请求的响应(以及新的会话 ID)。在这种情况下,程序化请求因此必须能够
- 1. Handle cookies (unless you force URL rewriting which is unlikely)
- 2. Detect when they get a 302 and login form back on the request and complete the required Form post before they continue.
- 1. 处理 cookie(除非你强制重写 URL,这是不太可能的)
- 2. 检测他们何时收到 302 和登录表单,并在继续之前完成所需的表单发布。
Alternatively, a Jersey specific solution is available by intercepting the calls, here:
或者,可以通过拦截呼叫获得泽西岛特定的解决方案,如下所示:
回答by Vasile Dirla
For me these changes solved the issue:
对我来说,这些变化解决了这个问题:
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);
回答by milosz
Autorization for JAAS:
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);
回答by Kamlendu Pandey
To access Rest End Point from Form Based Authentication One need to register a Form Authentication Filter with the JAX-RS Jersey client. One useful filter class is given at the following git hub link.
要从基于表单的身份验证访问 Rest End Point 需要向 JAX-RS Jersey 客户端注册一个表单身份验证过滤器。以下 git hub 链接提供了一个有用的过滤器类。
use FormAuthenticator.java in your project and in Rest Jersey client do the following:
在您的项目和 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");
}
And everything works fine. I have used it and this issue is solved. JAX-RS API must give this authenticator in their release.
一切正常。我用过,这个问题解决了。JAX-RS API 必须在其发行版中提供此身份验证器。
Note: same username and password which were used in form based authentication are to be supplied from calling client in servlets.
注意:在基于表单的身份验证中使用的相同用户名和密码将从 servlet 中的调用客户端提供。
as RestClient rs = new RestClient(username, password);
** Aplication class should register RolesAllowedDynamicFeature for roles to take effect ** MyApplication.java in Web Project where Rest class and FormAuthenticator.java resides rest package
** 应用类需要注册 RolesAllowedDynamicFeature 才能使角色生效 ** Web Project 中的 MyApplication.java Rest 类和 FormAuthenticator.java 所在的 rest 包
@ApplicationPath("webresources")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("entity.service");
packages("rest");
register(RolesAllowedDynamicFeature.class);
}
}