锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

加入spring sesion redis后,cookie无法跨域请求

时间:2023-01-20 20:30:00 sames电阻仪ap1000

springsecurity spring session redis

项目使用springsecurity进行认证和鉴权

因为项目每次部署登陆都会失败(session 认证机制)

故集成spring session redis将session保存在redis当中

集成完成后,发现认证成功后返回session-id登录后携带session-id不同导致认证成功

问题在于集成spring session redis 返回响应头 set-cookie上

此时SameSite的值为Lax,cookie部门场景不允许跨域

SameSite 属性

Cookie 的SameSite该属性用于限制第三方 Cookie,从而降低安全风险。

它可以设置三个值。

  • Strict
  • Lax
  • None

1 Strict

Strict第三方完全禁止最严格的 Cookie,任何情况下任何情况下都不会发送 Cookie。换句话说,只有当前的网页 URL 只有与请求目标一致,才会带上 Cookie。

Set-Cookie: CookieName=CookieValue; SameSite=Strict; 

这一规则过于严格,可能会导致非常糟糕的用户体验。例如,当前的网页有一个 GitHub 链接,用户点击跳转 GitHub 的 Cookie,跳转过去总是没有登。

2 Lax

Lax规则略有放宽,大多数情况下不发送第三方 Cookie,但导航到目标网站 Get 请求除外。

Set-Cookie: CookieName=CookieValue; SameSite=Lax; 

导航到目标网站 GET 只有三种情况:链接,预加载请求,GET 表单。详见下表。

请求类型 示例 正常情况 Lax
链接 发送 Cookie 发送 Cookie
预加载 发送 Cookie 发送 Cookie
GET 表单
发送 Cookie 发送 Cookie
POST 表单 发送 Cookie 不发送
iframe 发送 Cookie 不发送
AJAX $.get("...") 发送 Cookie 不发送
Image 发送 Cookie 不发送

设置了StrictLax以后基本杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。

3 None

Chrome 计划将Lax变成默认设置。此时,网站可以选择显式关闭。SameSite属性,设置为None。但前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

参考博文:Cookie 的 SameSite 属性

问题的原因及解决方案

1.当我们介绍它时spring session redis的依赖包spring-session-core包括时间session自动配置

@Bean         @Conditional({SessionAutoConfiguration.DefaultCookieSerializerCondition.class})         DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties, ObjectProvider cookieSerializerCustomizers) {             Cookie cookie = serverProperties.getServlet().getSession().getCookie();             DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();             PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();             cookie.getClass();             map.from(cookie::getName).to(cookieSerializer::setCookieName);             cookie.getClass();             map.from(cookie::getDomain).to(cookieSerializer::setDomainName);             cookie.getClass();             map.from(cookie::getPath).to(cookieSerializer::setCookiePath);             cookie.getClass();             map.from(cookie::getHttpOnly).to(cookieSerializer::setUseHttpOnlyCookie);             cookie.getClass();             map.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie);             cookie.getClass();             map.from(cookie::getMaxAge).to((maxAge) -> {                 cookieSerializer.setCookieMaxAge((int)maxAge.getSeconds());             });             cookieSerializerCustomizers.orderedStream().forEach((customizer) -> {                 customizer.customize(cookieSerializer);             });             return cookieSerializer;         }

上述代码从配置文件中读取cookie的用户自定义配置(一般是在application.yml中定义的)
然后新建了cookie序列化配置类
用户定义的参数通过PropertyMapper工具设置到cookie序列化配置类(有兴趣可以阅读)PropertyMapper源码,还是比较容易读懂的)

注入遍历mvc环境的cookieSerializerCustomizers调用接口法 void customize(DefaultCookieSerializer cookieSerializer)

注入DefaultCookieSerializer

2  注解分析 @Conditional({SessionAutoConfiguration.DefaultCookieSerializerCondition.class})

上述注释是条件注入的注释,DefaultCookieSerializerConditin继承了AnyNestedCondition,当DefaultCookieSerializerCondition中分段注解任一生效时,bean就会注入

DefaultCookieSerializerCondition具体代码如下:

static class DefaultCookieSerializerCondition extends AnyNestedCondition {
        DefaultCookieSerializerCondition() {
            super(ConfigurationPhase.REGISTER_BEAN);
        }

        @ConditionalOnBean({CookieHttpSessionIdResolver.class})
        @ConditionalOnMissingBean({CookieSerializer.class})
        static class CookieHttpSessionIdResolverAvailable {
            CookieHttpSessionIdResolverAvailable() {
            }
        }

        @ConditionalOnMissingBean({HttpSessionIdResolver.class, CookieSerializer.class})
        static class NoComponentsAvailable {
            NoComponentsAvailable() {
            }
        }
    }

3.再溯源到DefaultCookieSerializer类中,找到罪魁元首

4.解决方案

手写配置注入CookieSerializer

@Configuration
public class SpringSessionConfig {
    @Bean
    DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties, ObjectProvider cookieSerializerCustomizers) {
        Session.Cookie cookie = serverProperties.getServlet().getSession().getCookie();
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setSameSite(null);
        PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
        map.from(cookie::getName).to(cookieSerializer::setCookieName);
        map.from(cookie::getDomain).to(cookieSerializer::setDomainName);
        map.from(cookie::getPath).to(cookieSerializer::setCookiePath);
        map.from(cookie::getHttpOnly).to(cookieSerializer::setUseHttpOnlyCookie);
        map.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie);
        map.from(cookie::getMaxAge).to((maxAge) -> {
            cookieSerializer.setCookieMaxAge((int)maxAge.getSeconds());
        });
        cookieSerializerCustomizers.orderedStream().forEach((customizer) -> {
            customizer.customize(cookieSerializer);
        });
        return cookieSerializer;
    }

}

问题解决:

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章