我正在使用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令牌(由其私钥签名)。第二个微服务是资源服务器,它根据授权服务器公钥(由Auth服务器通过REST端点公开)验证令牌。
从授权服务器接收到access_token后是否要设置?您想通过设置Cookie来做什么?
不。我希望授权服务器在前端应用程序进行oauth/token
调用时设置cookie。这样,浏览器负责将令牌添加到每个请求,而不是我的前端应用程序。这将保护我免受XSS攻击,因为cookie将设置为httpOnly
和secure
。
您的计划是读取cookie以获取access_token吗?
正确。但这应该由资源服务器完成(尚未完成)
简单的方法是创建具有相同功能的API。它将access_token作为请求参数并设置cookie。
您是否建议在前端应用程序和身份验证/资源服务器之间使用代理微服务之类的东西?将jwt令牌设置为cookie并从cookie读取令牌的代理微服务?
答案 0 :(得分:2)
不。我希望授权服务器在前端应用程序进行oauth / token调用时设置cookie。
您需要在所有过滤器之前添加过滤器,我的意思是过滤器顺序为1,以便请求首先到达并最后调度。
如果不是spring-boot,则使用web.xml或spring配置的java config方式会容易得多。由于Spring Boot不依赖web.xml,因此所有过滤器都是代理过滤器,除了DelegatingFilterProxy(springSecurityFilterChain)之前,我们无法添加任何过滤器。
满足要求的可能方法是在FilterRegistrationBean
中将order(1)注册为过滤器。
提供过滤器网址格式/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();
}
}
}
您可以控制响应对象并添加cookie。仅显示日志以供参考。