Как сделать базовую аутентификацию с использованием куки в Spring Security? - PullRequest
0 голосов
/ 09 февраля 2019

Я защищаю свой REST API с помощью Basic-Auth.На правильных учетных данных, переданных пользователем, контроллер отвечает за отправку файлов cookie httpOnly и secure в ответ.

@GetMapping
@ResponseStatus(value=HttpStatus.OK)
public void loginUser( final HttpServletRequest request ,final HttpServletResponse response) throws UnsupportedEncodingException {

    setAuthCookieToResonse(request,response);

}

private void setAuthCookieToResonse(final HttpServletRequest request ,final HttpServletResponse response) throws UnsupportedEncodingException {
    String cookieKey = "auth";
    String cookieValue = request.getHeader("Authorization");

    if (cookieValue != null) {
        Cookie cookie = new Cookie(cookieKey, cookieValue);
        cookie.setHttpOnly(true);
        cookie.setSecure(true);

        response.addCookie(cookie);
    }
}

Итак, теперь с каждым запросом браузер отправляет cookie, которыйбудет содержать Basic-Auth детали.Но проблема в том, как Spring Security извлекает эти учетные данные из этого cookie-файла?

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {// @formatter:off 
        httpSecurity
        .cors()
        .and().authorizeRequests()
        .antMatchers("/signup/**").permitAll()
        .anyRequest().authenticated()
        .and().httpBasic()
        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and().csrf().disable()
        ;
     }

Я предположил:
Чтобы добавить фильтр до BasicAuthenticationFilter.class и извлечь учетные данные из cookie иЗатем добавьте эти учетные данные в заголовок HttpServletRequest Authorizaton, который будет передан на уровень безопасности Spring.Но проблема в том, что HttpServletRequest не имеет API для добавления заголовков.

Как правильно это реализовать?

1 Ответ

0 голосов
/ 11 февраля 2019

Я сделал это, работая после этого блога .Но я бы хотел услышать других решений, особенно с использованием какой-либо пружинной конфигурации .Spring - очень зрелая структура, она должна (должна) иметь что-то для решения этой распространенной проблемы.

Так как HttpServletRequest не имеет никакого метода для добавления новых заголовков, мне нужно создать собственный класс, который может добавлять новые заголовки к запросу, этого можно достичь с помощью HttpServletRequestWrapper.Вот реализация.

public final class MutableHttpServletRequest extends HttpServletRequestWrapper {
    // holds custom header and value mapping
    private final Map<String, String> customHeaders;

    public MutableHttpServletRequest(HttpServletRequest request) {
        super(request);
        this.customHeaders = new HashMap<String, String>();
    }

    public void putHeader(String name, String value) {
        this.customHeaders.put(name, value);
    }

    public String getHeader(String name) {
        // check the custom headers first
        String headerValue = customHeaders.get(name);

        if (headerValue != null) {
            return headerValue;
        }
        // else return from into the original wrapped object
        return ((HttpServletRequest) getRequest()).getHeader(name);
    }

    public Enumeration<String> getHeaderNames() {
        // create a set of the custom header names
        Set<String> set = new HashSet<String>(customHeaders.keySet());

        // now add the headers from the wrapped request object
        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
        while (e.hasMoreElements()) {
            // add the names of the request headers into the list
            String n = e.nextElement();
            set.add(n);
        }

        // create an enumeration from the set and return
        return Collections.enumeration(set);
    }
}

Фильтр, который проверяет наличие cookie до Spring-secuirty:

public class CheckAuthCookieFilter implements Filter {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(httpServletRequest);

        Cookie[] cookies = httpServletRequest.getCookies();

        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                logger.debug(cookie.getName() + " : " + cookie.getValue());
                if (cookie.getName().equalsIgnoreCase("auth")) {
                    mutableRequest.putHeader("Authorization", URLDecoder.decode(cookie.getValue(), "utf-8"));
                }
            }
        }

        chain.doFilter(mutableRequest, response);

    }

}

и, наконец, конфигурация безопасности:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {// @formatter:off 
    httpSecurity
    .cors()
    .and().authorizeRequests()
    .antMatchers("/signup/**").permitAll()
    .anyRequest().authenticated()
    .and().httpBasic()
    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and().csrf().disable()
    ;

    httpSecurity.addFilterBefore(new CheckAuthCookieFilter(), BasicAuthenticationFilter.class); 

}

Мой настраиваемый фильтр будет работать до BasicAuthenticationFilter Spring. Если присутствует файл cookie с именем auth (который приложение создало при успешном входе в систему), то это файл cookie, который содержит базовые учетные данные аутентификации.Из этого извлекаются учетные данные и добавляются в заголовок request.Затем BasicAuthenticationFilter будет работать и искать Authorization и продолжить его нормальный поток.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...