java 使用 Jersey / Grizzly 进行基本 HTTP 身份验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14608162/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 16:48:35  来源:igfitidea点击:

Basic HTTP authentication with Jersey / Grizzly

javajerseyjax-rshttp-authenticationgrizzly

提问by aioobe

I've written a simple REST server using JAX-RS, Jersey and Grizzly. This is how I start the server:

我已经使用 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);

Now I need to protect the resources using Basic HTTP authentication, and I can't figure out how to do this.

现在我需要使用基本 HTTP 身份验证来保护资源,但我不知道如何做到这一点。

I can switch from Grizzly to for instance Jetty if it is simpler to get it to work, but I really value the simple configuration / start up that Grizzly provides.

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

I've read a lot of tutorials. They all mention the web.xml but in my current configuration I don't have one. (Do I need to add one for HTTP authentication?) I've found the followingquestions, neither of them is of any help :-(

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

(No SSL required at this point. The authentication is at this point just to prevent the public from peeking at our beta.)

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

TL;DR: How do I add basic HTTP authentication to a Jersey / Grizzly webapp?

TL;DR:如何将基本的 HTTP 身份验证添加到 Jersey/Grizzly 网络应用程序?

采纳答案by aioobe

I managed to get it working after a couple of hours, based on this blog post.

根据这篇博客文章,我设法在几个小时后让它工作。

My solution involves:

我的解决方案包括:

  • Maven artifacts:
    • jersey-server (v 1.17)
    • jersey-grizzly2 (v 1.17)
  • Hard coded username / password (replace with database lookup if you like)
  • No web.xml (programatically configured server)
  • No SSL involved
  • Maven 工件:
    • 球衣服务器 (v 1.17)
    • jersey-grizzly2 (v 1.17)
  • 硬编码的用户名/密码(如果您愿意,可以替换为数据库查找)
  • 没有 web.xml(以编程方式配置的服务器)
  • 不涉及 SSL

I created this ContainerRequestFilter:

我创建了这个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;
    }
}

And I then changed the startup code to include the filter:

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

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

回答by Arul Dhesiaseelan

You may want to check HTTPS Client Server Grizzly sampledistributed with Jersey which exactly does that. Here is a gist from that sample on configuring security filters on the Grizzly server.

您可能想要检查与 Jersey 一起分发的HTTPS Client Server Grizzly示例,它正是这样做的。以下是该示例中有关在 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());
    }

You are registering a SecurityFilter which takes care of your HTTP basic auth. Enabling logging filter on the server should show basic auth header in the request. Here is an example:

您正在注册一个 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

回答by jgm

@aioobe be aware that although this will kind-of work you need better error checking when you're working with the header. For example:

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

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

This assumes that the authentication header is Basic, whereas it might not be. You should check that the authorization header starts with 'Basic' and if not throw unauthorized. Same thing for ensuring that the rest of the information is actually base64-encoded.

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