繁体   English   中英

如何使用RESTEasy显示用于基本身份验证的浏览器登录表单

[英]How to show browser login form for basic authentication using 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();
    }
}

与邮递员一起使用效果很好。 而且我确实意识到此类api的主要用法是在其他程序中。

但这很好,如果在浏览器中打开它,它会要求您输入凭据,而不仅仅是告诉您您没有授权,而无法真正输入凭据。 除非您做了一些技巧来手动将其放在标题中,否则您最好只使用邮递员。

如果我将安全性约束与auth-constraint角色admin放在一起,它的确会显示一个登录对话框,但是授权不起作用,它只会继续询问授权。

我还有什么可以代替containerRequestContext.abortWith吗? 还是我需要使用一种完全不同的方法,并且它不能与ContainerRequestFilter一起使用?

您需要将WWW-Authenticate标头添加到中止的响应中。 此标头告诉浏览器应提供默认的浏览器登录表单。

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上的登录外观

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM