java - 如何使用 RESTEasy 显示浏览器登录表单以进行基本身份验证

标签 java jax-rs basic-authentication resteasy

我目前正在使用 JAX-RS,特别是 Resteasy,因为它“只适用于”Wildfly,而且我不需要配置任何东西。这确实是我使用它的唯一原因。

我已经实现了基本身份验证,期待稍后将其替换为 OAuth2,出于简单原因现在才这样做。

ContainerRequestFilter 看起来像这样

    @Provider
    public class SecurityFilter implements ContainerRequestFilter {

    private static final String AUTHORIZATION_HEADER_KEY = "Authorization";
    private static final String AUTHORIZATION_HEADER_PREFIX = "Basic ";

    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException {

        if(isAuthenticated(containerRequestContext) == false)
            containerRequestContext.abortWith(createUnauthorizedResponse("Access denied."));
    }

    private boolean isAuthenticated(ContainerRequestContext containerRequestContext) {
        List<String> authHeader = containerRequestContext.getHeaders().get(AUTHORIZATION_HEADER_KEY);

        ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) containerRequestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
        Method method = methodInvoker.getMethod();
        RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);

        if (authHeader != null && authHeader.size() > 0) {
            String authToken = authHeader.get(0).replaceFirst(AUTHORIZATION_HEADER_PREFIX, "");

            byte[] decoded = null;

            try {
                decoded = Base64.getDecoder().decode(authToken);
            } catch (IllegalArgumentException ex) {
                return false;
            }

            String decodedString = new String(decoded);
            StringTokenizer tokenizer = new StringTokenizer(decodedString, ":");

            String username = null, password = null;

            if(tokenizer.countTokens() < 2)
                return false;

            username = tokenizer.nextToken();
            password = tokenizer.nextToken();

            if (DbController.isValid(username, password, rolesAnnotation.value()))
                return true;
        }

        return false;
    }

    private Response createUnauthorizedResponse(String msg) {
        return Response.status(Response.Status.UNAUTHORIZED)
                .entity("{ \"Unauthorized\" : \"" + msg + "\" }")
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
}

它与 postman 配合得很好。我确实意识到此类 api 的主要用途是在其他程序中。

但是如果在浏览器中打开它会很好,它会要求您输入凭据,而不是仅仅告诉您您没有获得授权,无法真正输入您的凭据。除非您采取一些技巧手动将其放入 header 中,否则您不妨使用 postman 。

如果我使用身份验证约束角色管理员设置安全约束,它确实会提供一个登录对话框,但随后授权不起作用,它只是不断请求授权。

除了containerRequestContext.abortWith之外,我还能做些什么吗?或者我是否需要使用完全不同的方法,但它不适用于 ContainerRequestFilter?

最佳答案

您需要添加 WWW-Authenticate您中止的响应的 header 。此 header 告诉浏览器应该显示默认的浏览器登录表单。

private static final String CHALLENGE_FORMAT = "%s realm=\"%s\"";

private Response createUnauthorizedResponse() {
    return Response.status(Response.Status.UNAUTHORIZED)
            .header(HttpHeaders.WWW_AUTHENTICATE, String.format(CHALLENGE_FORMAT, "Basic", "Access"))
            .type(MediaType.TEXT_PLAIN_TYPE)
            .entity("Credentials are required to access this resource.")
            .build();

这是 Chrome 上的登录界面

enter image description here

关于java - 如何使用 RESTEasy 显示浏览器登录表单以进行基本身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50376404/

相关文章:

azure - 从Azure功能安全地调用Web Api

java - REST添加子资源

java - 如何在 Cloudera hadoop 中使用外部 jar?

Java,检查是否为int,如果是则执行某些操作,如果不是int则忽略

java - 尝试编译 Telegram 源代码时找不到文件

java - 使用 ObjectMapper 添加 JAR 会使我的 ObjectMapper 不可发现

glassfish - JAX-RS 自定义路径参数验证器

java - 如何获得在 WebSphere 上运行的基本身份验证?

node.js - 如何让 express-basic-auth 提示弹出用户和密码?

java - 如何在 Eclipse 中配置 Java -D 标志