Spring security oauth2 - добавить фильтр после вызова oauth / token - PullRequest
2 голосов
/ 11 октября 2019

Я использую Spring Boot 2.1.1.RELEASE (spring-security-oauth2 - 2.3.4.RELEASE).

Я хотел бы создать фильтр с приоритетом после вызова TokenEndpoint#postAccessToken. Почему ? потому что в этом фильтре я хочу взять токен из tokenStore и добавить его в качестве файла cookie к ответу.

Я ожидаю, что это даст мне то, что я хочу:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .(...)
    .addFilterAfter(new MyFilter(), BasicAuthenticationFilter.class);
}

Но это не так. Я вижу, что BasicAuthenticationFilter вызывается после успешной аутентификации на oauth/token, но он не входит в мой MyFilter.

Что я должен делать, чтобы позвонить MyFilter после oauth/token вызова?


Вы хотите установить cookie с сервера авторизации или с сервера ресурсов? Ваш сервер аутентификации и сервер ресурсов оба находятся в одном контексте? или другие приложения .?

У меня есть два микросервиса. Первый - это сервер авторизации, который предоставляет токены jwt (подписанные его закрытым ключом). Второй микросервис - это сервер ресурсов, который проверяет токены на основе открытого ключа сервера авторизации (предоставляется через конечную точку REST сервером аутентификации)

Вы хотите установить после получения access_token от сервера авторизации? Что> вы хотите сделать, установив cookie?

Нет. Я хотел бы, чтобы сервер авторизации установил cookie, когда oauth/token вызов сделан внешним приложением. Таким образом, браузер отвечает за добавление токена в каждый запрос, а не за мое приложение. Это защищает меня от XSS-атаки, так как для файла cookie будут установлены значения httpOnly и secure.

Планируется ли чтение файла cookie для получения access_token?

Верный. Но это должно быть сделано сервером ресурсов (еще не сделали этого)

простой способ - создать API для той же функциональности. Который принимает access_token в качестве параметра запроса и устанавливает cookie.

Вы предлагаете что-то вроде прокси-микросервиса, который стоит между внешним приложением и серверами аутентификации / ресурсов? прокси-микросервис, который устанавливает токен jwt как cookie и читает токен из cookie?

1 Ответ

2 голосов
/ 11 октября 2019

Нет. Я хотел бы, чтобы сервер авторизации установил cookie при вызове oauth / token приложением внешнего интерфейса.

Вам необходимо добавить фильтр перед всеми фильтрами, я имею в виду порядок фильтров 1, чтобы запрос сначала достиг ипоследние рассылки.

Если бы это не было весенней загрузкой, это было бы намного проще с помощью web.xml или java config способа конфигурации Spring. Поскольку весенняя загрузка не полагается на web.xml, все фильтры являются прокси-фильтрами, кроме DelegatingFilterProxy (springSecurityFilterChain), до этого мы не можем добавлять какие-либо фильтры.

  • Возможным способом удовлетворения ваших требований является регистрацияфильтр в FilterRegistrationBean с порядком (1).

  • Дайте шаблон URL фильтра /oauth/token

  • В вашем фильтре используйте HttpServletResponseWrapperреализация для чтения ответа и получения access_token и установки cookie согласно вашему требованию.

In Any configuration class register filter into FilterRegistrationBean
@Configuration
public class AppInitializer
{
    @Bean
    public FilterRegistrationBean<AccessTokenAlterFilter> sessionTimeoutFilter()
    {
        FilterRegistrationBean<AccessTokenAlterFilter> registrationBean = new FilterRegistrationBean<>();
        AccessTokenAlterFilter filter = new AccessTokenAlterFilter();

        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns("/oauth/token");
        registrationBean.setOrder(1); // set precedence
        return registrationBean;
    }
}
Your Filter
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AccessTokenAlterFilter implements Filter
{

    Logger OUT = LoggerFactory.getLogger(AccessTokenAlterFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
    {
        OUT.info("[[[[[[[[[[[[STARTED]]]]]]]]]]]]]]");

        CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response);
        chain.doFilter(request, wrappedResponse);
        byte[] bytes = wrappedResponse.getByteArray();
        String out = new String(bytes);
        OUT.info("Response String: {}", out);

        response.getOutputStream().write(out.getBytes());

        OUT.info("[[[[[[[[[[[[ENDED]]]]]]]]]]]]]]");
    }

    private static class ByteArrayServletStream extends ServletOutputStream
    {
        ByteArrayOutputStream baos;

        ByteArrayServletStream(ByteArrayOutputStream baos)
        {
            this.baos = baos;
        }

        public void write(int param) throws IOException
        {
            baos.write(param);
        }

        @Override
        public boolean isReady()
        {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener listener)
        {}
    }

    private static class ByteArrayPrintWriter
    {
        private ByteArrayOutputStream   baos    = new ByteArrayOutputStream();
        private PrintWriter             pw      = new PrintWriter(baos);
        private ServletOutputStream     sos     = new ByteArrayServletStream(baos);

        public PrintWriter getWriter()
        {
            return pw;
        }

        public ServletOutputStream getStream()
        {
            return sos;
        }

        byte[] toByteArray()
        {
            return baos.toByteArray();
        }
    }

    public class CharResponseWrapper extends HttpServletResponseWrapper
    {
        private ByteArrayPrintWriter    output;
        private boolean                 usingWriter;

        public CharResponseWrapper(HttpServletResponse response)
        {
            super(response);
            usingWriter = false;
            output = new ByteArrayPrintWriter();
        }

        public byte[] getByteArray()
        {
            return output.toByteArray();
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException
        {
            if (usingWriter)
            {
                super.getOutputStream();
            }
            usingWriter = true;
            return output.getStream();
        }

        @Override
        public PrintWriter getWriter() throws IOException
        {
            if (usingWriter)
            {
                super.getWriter();
            }
            usingWriter = true;
            return output.getWriter();
        }

        public String toString()
        {
            return output.toString();
        }
    }
}

Предыдущий поток все еще будет там, как указано ниже
enter image description here

Вы можете получить под контролем объект ответа и добавитьпеченье. Просто показаны журналы для справки.

enter image description here

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