java - 将相同的站点 header 添加到 JSESSIONID Spring Security

标签 java spring spring-boot spring-security

Google Chrome 浏览器引入了需要设置 Same-Site header 的更改。为了实现这一点,我添加了一个自定义过滤器,如下所示,

public class SameSiteFilter extends GenericFilterBean {
    private Logger LOG = LoggerFactory.getLogger(SameSiteFilter.class);

    @Override
    public void doFilter(ServletRequest request,  ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse resp = (HttpServletResponse)response;
        response = addSameSiteCookieAttribute((HttpServletResponse) response);
        chain.doFilter(request, response);
    }    

    private HttpServletResponse addSameSiteCookieAttribute(HttpServletResponse response) {
        Collection<String> header = response.getHeaders(HttpHeaders.SET_COOKIE);
        LOG.info(String.format("%s; %s", header, "SameSite=None; Secure"));
        response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=None; Secure"));

        return response;
    }
}

以下是安全配置的代码

@Configuration
@EnableWebMvcSecurity
public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { 
    @Autowired
    private OnyxUserDetailsService onyxUserDetailsService;

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/rest/user", "/info/**/*","/rest/version/check")
                .permitAll().antMatchers("/data/**/*")
                .access("hasRole('ROLE_ADMIN')").anyRequest()
                .fullyAuthenticated().and().httpBasic().realmName("ADOBENET")
                .and().logout().
                logoutSuccessHandler((new LogoutSuccessHandler() {

                    @Override
                    public void onLogoutSuccess(HttpServletRequest request,
                            HttpServletResponse response, Authentication authentication)
                            throws IOException, ServletException {
                        response.setStatus(HttpStatus.OK.value());
                        response.getWriter().flush();
                    }
                })).deleteCookies("JSESSIONID", "XSRF-TOKEN")
                .invalidateHttpSession(true).logoutUrl("/rest/logout")
                .logoutSuccessUrl("/rest/user").and()
                .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)   
                .addFilterAfter(new SameSiteFilter(), BasicAuthenticationFilter.class)          
                .csrf().disable();
    }

    @Override
    @Order(Ordered.HIGHEST_PRECEDENCE)
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }
}

但是,当我查看收到的 header 时,我明白了

enter image description here

过滤器会在所有响应中添加必填字段,但包含 JSESSIONID cookie 的响应除外。如何将 header 添加到此 cookie。我尝试配置 tomcat 设置,但我们将代码部署为 WAR 文件,因此也不起作用。

最佳答案

为了解决这个问题,我添加了一个过滤器来筛选所有响应。这是相同的代码,

@Component
public class SameSiteFilter implements Filter {
    private Logger LOG = LoggerFactory.getLogger(SameSiteFilter.class);

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        LOG.info("Same Site Filter Initializing filter :{}", this);
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        LOG.info("Same Site Filter Logging Response :{}", res.getContentType());

        Collection<String> headers = res.getHeaders(HttpHeaders.SET_COOKIE);
        boolean firstHeader = true;
        for (String header : headers) { // there can be multiple Set-Cookie attributes
            if (firstHeader) {
                res.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s",  header, "SameSite=None"));
                LOG.info(String.format("Same Site Filter First Header %s; %s", header, "SameSite=None; Secure"));

                firstHeader = false;
                continue;
            }

            res.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s",  header, "SameSite=None"));
            LOG.info(String.format("Same Site Filter Remaining Headers %s; %s", header, "SameSite=None; Secure"));
        }

        chain.doFilter(req, res);
    }

    @Override
    public void destroy() {
        LOG.warn("Same Site Filter Destructing filter :{}", this);
    }
}

这允许在包含 cookie 的响应中添加所需的 header

关于java - 将相同的站点 header 添加到 JSESSIONID Spring Security,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60865649/

相关文章:

java - 遍历耶拿的匿名/空白节点

java - Spring AOP @AfterThrowing 无法正常工作,错误于::0 切入点中正式未绑定(bind)

java - 基于文件的 h2 持久化但未在 Spring Boot 中加载

java - 如何在 Fragment 上初始化 Google AdMob 横幅

java - 将 java.sql.Connection 转换为 com.mysql.jdbc.Connection

java - ClassNotFoundException - org.aspectj.lang.annotation.Around

java - H2 数据库仅在文件中不能在内存中工作

java - 使用 MockMvc 时主体为空

java - Spring Security - 使用自定义数据库授权和 Auth0 预身份验证

java - 如何将图像添加到抽屉 View 的底部?