Как показать форму входа в браузер для базовой аутентификации с использованием RESTEasy - PullRequest
0 голосов
/ 16 мая 2018

В настоящее время я работаю с 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-интерфейсов есть и в других программах.

Но было бы неплохо, если бы при открытии в браузере он попросил бы вас ввести свои учетные данные, а не просто сказать, что выне авторизованы, без возможности реально ввести свои учетные данные.Если вы не сделаете какую-то хитрость, чтобы вручную поместить его в заголовок, но тогда вы могли бы также просто использовать почтальон.

Если я наложу ограничение безопасности на роль администратора с ограничением авторизации, оно выдаст диалог входа в систему, но затемавторизация не работает и просто продолжает запрашивать авторизацию.

Есть ли что-то еще, что я могу сделать вместо containerRequestContext.abortWith?Или мне нужно использовать совершенно другой подход, и он просто не будет работать с ContainerRequestFilter?

1 Ответ

0 голосов
/ 17 мая 2018

Вам нужно добавить заголовок 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

enter image description here

...