在客户端和服务器上使用Jersey实施基本身份验证

时间:2018-01-06 15:38:06

标签: java jax-rs basic-authentication jersey-2.0 jersey-client

我已经使用JAX-RS实现了一个REST服务器,它提供了一些使用x-www-form-urlencoded数据并使用XML响应的端点。

我有两个客户端:浏览器中的HTML页面和使用Jersey 2客户端API发送请求的Java客户端。

到目前为止,每件事都很好。现在,当我尝试在服务器和客户端上实现基本身份验证时,事情开始变得棘手。我的第一种方法是使用servlet身份验证工作正常。我在tomcat-users.xml中添加了用户和角色,并在我的服务器的web.xml中启用了基本身份验证。

问题是我必须在javax.servlet.Filter中为此练习实现应用程序级别身份验证。因此,基本上过滤器应拦截对服务器的任何请求,并针对包含有效用户凭证的HashMap检查Base64解码的“授权”标头内容,如果未找到匹配则使用401状态代码进行响应。

令人惊讶的是,这有效。 但只要我保持servlet身份验证运行。一旦我停用servlet级别身份验证,我的应用程序级别身份验证就不再起作用了。我已经检查过我的过滤器没有被忽略,方法是在Hashmap中添加未包含在tomcat-users.xml中的条目,反之亦然。只有具有通过servlet身份验证和我自己的身份验证的凭据才能将其发送到服务器。

调试显示,一旦关闭servlet身份验证,所有请求都会错过Authorization标头。我的猜测是,servlet身份验证会以某种方式弥补我所犯的错误并“修复”我的请求,但我看不出如何。

以下是相关的客户端代码:

HttpAuthenticationFeature httpAuthenticationFeature =
        HttpAuthenticationFeature
        .basic("ceo", "123456");

ClientConfig clientConfig = new ClientConfig();
clientConfig.register(httpAuthenticationFeature);
javax.ws.rs.client.Client client = ClientBuilder.newClient(clientConfig);

webTarget = client.target("http://" + hostname + ":" + port)
        .property(HttpAuthenticationFeature.HTTP_AUTHENTICATION_BASIC_USERNAME, "ceo")
        .property(HttpAuthenticationFeature.HTTP_AUTHENTICATION_BASIC_PASSWORD, "123456")
        .path("RESTService");

Form form = new Form();
form.param("field1", value1);
form.param("field2", value2);

String response = webTarget.path("rest").path("service").path("endpoint")
        .request(MediaType.APPLICATION_XML)
        .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), String.class);

这是服务器代码:

@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements javax.servlet.Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest)request;
        String authCredentials = req.getHeader(HttpHeaders.AUTHORIZATION);

        // authenticate() returns true if credentials are valid
        if (authenticate(authCredentials))      
            chain.doFilter(request, response);

        // should return proper 401 response, but apparently does not
        // as browser shows no prompt for credentials
        else if (response instanceof HttpServletResponse) {
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    }

    // ...
}

提前致谢!

0 个答案:

没有答案