【问题标题】:Basic HTTP authentication with Jersey / GrizzlyJersey / Grizzly 的基本 HTTP 身份验证
【发布时间】:2013-01-14 12:20:34
【问题描述】:

我使用 JAX-RS、Jersey 和 Grizzly 编写了一个简单的 REST 服务器。这就是我启动服务器的方式:

URI baseUri = UriBuilder.fromUri("http://localhost/api")
                        .port(8081)
                        .build();

ResourceConfig rc = new PackagesResourceConfig("se.aioobe.resources");
HttpServer httpServer = GrizzlyServerFactory.createHttpServer(baseUri, rc);

现在我需要使用基本 HTTP 身份验证来保护资源,但我不知道该怎么做。

如果让 Grizzly 工作更简单,我可以从 Grizzly 切换到例如 Jetty,但我非常重视 Grizzly 提供的简单配置/启动。

我已经阅读了很多教程。他们都提到了 web.xml,但在我目前的配置中我没有。 (我需要为 HTTP 身份验证添加一个吗?)我找到了 following questions,它们都没有任何帮助:-(

(此时不需要 SSL。此时的身份验证只是为了防止公众偷看我们的测试版。)

TL;DR:如何将基本 HTTP 身份验证添加到 Jersey / Grizzly webapp?

【问题讨论】:

  • 您想在容器级别上拥有,还是 JAX-RS 级别也可以?
  • 那么你是如何解决这个问题的呢?因为我也有同样的问题。
  • 如果某个问题的答案已被接受,您可以放心地假设这就是 OP 解决问题的方式。在这种情况下,我什至自己发布了答案。

标签: java jersey jax-rs http-authentication grizzly


【解决方案1】:

根据this blog post,我设法在几个小时后让它工作。

我的解决方案包括:

  • Maven 工件:
    • 球衣服务器 (v 1.17)
    • jersey-grizzly2 (v 1.17)
  • 硬编码的用户名/密码(如果你愿意,可以用数据库查找代替)
  • 没有 web.xml(以编程方式配置的服务器)
  • 不涉及 SSL

我创建了这个ContainerRequestFilter

public class AuthFilter implements ContainerRequestFilter {

    // Exception thrown if user is unauthorized.
    private final static WebApplicationException unauthorized =
       new WebApplicationException(
           Response.status(Status.UNAUTHORIZED)
                   .header(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"realm\"")
                   .entity("Page requires login.").build());

    @Override
    public ContainerRequest filter(ContainerRequest containerRequest) 
            throws WebApplicationException {

        // Automatically allow certain requests.
        String method = containerRequest.getMethod();
        String path = containerRequest.getPath(true);
        if (method.equals("GET") && path.equals("application.wadl"))
            return containerRequest;

        // Get the authentication passed in HTTP headers parameters
        String auth = containerRequest.getHeaderValue("authorization");
        if (auth == null)
            throw unauthorized;

        auth = auth.replaceFirst("[Bb]asic ", "");
        String userColonPass = Base64.base64Decode(auth);

        if (!userColonPass.equals("admin:toHah1ooMeor6Oht"))
            throw unauthorized;

        return containerRequest;
    }
}

然后我更改了启动代码以包含过滤器:

URI baseUri = UriBuilder.fromUri("http://localhost/api")
                        .port(8081)
                        .build();

ResourceConfig rc = new PackagesResourceConfig("se.aioobe.resources");

// Add AuthFilter ////////////
rc.getProperties().put("com.sun.jersey.spi.container.ContainerRequestFilters",
                       "<YOUR PACKAGE FOR AuthFilter>.AuthFilter");
//////////////////////////////

HttpServer httpServer = GrizzlyServerFactory.createHttpServer(baseUri, rc);

【讨论】:

    【解决方案2】:

    您可能需要检查与 Jersey 一起分发的 HTTPS 客户端服务器 Grizzly sample 正是这样做的。以下是该示例中关于在 Grizzly 服务器上配置安全过滤器的要点。

        WebappContext context = new WebappContext("context");
        ServletRegistration registration = 
                context.addServlet("ServletContainer", ServletContainer.class);
        registration.setInitParameter("com.sun.jersey.config.property.packages",
                "com.sun.jersey.samples.https_grizzly.resource;com.sun.jersey.samples.https_grizzly.auth");
    
        // add security filter (which handles http basic authentication)
        registration.setInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS,
                "com.sun.jersey.samples.https_grizzly.auth.SecurityFilter;com.sun.jersey.api.container.filter.LoggingFilter");
        registration.setInitParameter(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS,
                LoggingFilter.class.getName());
    
    
        try {
    
            webServer = GrizzlyServerFactory.createHttpServer(
                    getBaseURI()
            );
    
            // start Grizzly embedded server //
            System.out.println("Jersey app started. Try out " + BASE_URI + "\nHit CTRL + C to stop it...");
            context.deploy(webServer);
            webServer.start();
    
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    

    您正在注册一个 SecurityFilter 来处理您的 HTTP 基本身份验证。在服务器上启用日志过滤器应在请求中显示基本身份验证标头。这是一个例子:

    Jan 30, 2013 8:59:00 PM com.sun.jersey.api.container.filter.LoggingFilter filter
    INFO: 1 * Server in-bound request
    1 > GET http://localhost:8080/context/
    1 > host: localhost:8080
    1 > connection: keep-alive
    1 > cache-control: max-age=0
    1 > authorization: Basic dXNlcjpwYXNzd29yZA==
    1 > accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    1 > user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17
    1 > accept-encoding: gzip,deflate,sdch
    1 > accept-language: en-US,en;q=0.8
    1 > accept-charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
    1 > 
    
    Service: GET / User: user
    Jan 30, 2013 8:59:00 PM com.sun.jersey.api.container.filter.LoggingFilter$Adapter finish
    INFO: 1 * Server out-bound response
    1 < 200
    1 < Content-Type: text/html
    1 < 
    JERSEY HTTPS EXAMPLE
    

    【讨论】:

    • 谢谢!我确实调查过。即使在我的 mvn 存储库中手动安装了一堆 jar 文件后,我也无法编译它。我确实根据类似的代码让它最终工作。我会在一分钟左右发布答案。
    【解决方案3】:

    @aioobe 请注意,尽管这会起作用,但在使用标头时需要更好的错误检查。例如:

        auth = auth.replaceFirst("[Bb]asic ", "");
    

    这假定身份验证标头是基本的,但它可能不是。您应该检查授权标头是否以“基本”开头,如果不是未经授权则抛出。确保其余信息实际上是 base64 编码的也是如此。

    【讨论】:

    • 谢谢你。我同意 100%。
    猜你喜欢
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 2011-11-12
    • 2011-05-05
    相关资源
    最近更新 更多