前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Servlet 设置 cookie 的 SameSite 属性

使用 Servlet 设置 cookie 的 SameSite 属性

作者头像
MashiroT
发布2022-10-28 08:47:15
5.5K1
发布2022-10-28 08:47:15
举报
文章被收录于专栏:MashiroのBlog

引入

最近学习了Servlet、Mybatis、Vue,想手搓一个用户登录界面+数据展示后台,但是在记住用户登录 设置cookie的时候遇到的问题。问题是:使用 HttpServletResponseaddCookie() 方法后,开发者工具提示 某些 Cookie 滥用推荐的"sameSite"属性 由于 Cookie 的"sameSite"属性设置为"none",但缺少"secure"属性,此 Cookie 未来将被拒绝。

解法1 使用Filter过滤器 推荐

创建一个Filter类,重写doFilter方法

代码语言:javascript
复制
package ski.mashiro.web.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Collection;

// "/*"代表过滤根路径下的所有访问,即给每个cookie添加SameSite属性
@WebFilter("/*")
public class SameSiteFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);
        // add SameSite=strict cookie attribute
        addSameSiteAttribute((HttpServletResponse) response);
    }
    private void addSameSiteAttribute(HttpServletResponse response) {
        Collection<String> headers = response.getHeaders("Set-Cookie");
        boolean firstHeader = true;
        for (String header : headers) {
            if (firstHeader) {
                response.setHeader("Set-Cookie", String.format("%s; %s", header, "SameSite=Strict"));
                firstHeader = false;
                continue;
            }
            response.addHeader("Set-Cookie", String.format("%s; %s", header, "SameSite=Strict"));
        }
    }
    @Override
    public void destroy() {
    }
}

解法2 继承Cookie类,添加SameSite属性 不推荐

代码语言:javascript
复制
package xxx.xxx.common.controller;
 
import javax.servlet.http.Cookie;
 
/**
 * @author himans 2020-6-5
 */
public class NewCookie extends Cookie {
   private String sameSite;
   public final static String LAX = "Lax";
   public final static String NONE = "None";
   public final static String STRICT = "Strict";
   public final static String SET_COOKIE = "Set-Cookie";
 
   public NewCookie(String name, String value) {
      super(name, value);
   }
 
   public String getSameSite() {
      return sameSite;
   }
 
   public NewCookie setSameSite(String sameSite) {
      this.sameSite = sameSite;
      if (NONE.equals(sameSite)) {
         setSecure(true);
      }
      return this;
   }
 
   @Override
   public String toString() {
      // 参照Controller中的doSetCookie代码
      StringBuilder sb = new StringBuilder(getName()).append("=").append(getValue());
      sb.append(";Path=").append(getPath()==null?"/":getPath());
      if (getDomain() != null) {
         sb.append(";Domain=").append(getDomain());
      }
      if (isHttpOnly()) {
         sb.append(";HttpOnly");
      }
      sb.append(";Max-Age=").append(getMaxAge());
      // 默认Lax
      sb.append(";SameSite=").append(getSameSite()==null?"Lax":getSameSite());
      if (getSecure()) {
         sb.append(";Secure");
      }
      if (getComment() != null) {
         sb.append(";Comment=").append(getComment());
      }
 
      return sb.toString();
   }
}

修改LoginController中的doLogin代码:

代码语言:javascript
复制
/**
 * 登录
 */
@Before(LoginValidator.class)
public void doLogin() {
    boolean keepLogin = getParaToBoolean("keepLogin", false);
    String loginIp = IpKit.getRealIp(getRequest());
    Ret ret = srv.login(getPara("userName"), getPara("password"), keepLogin, loginIp);
    if (ret.isOk()) {
        String sessionId = ret.getStr(LoginService.COOKIE_SESSION_NAME);
        int maxAgeInSeconds = ret.getInt("maxAgeInSeconds");
        // setCookie(LoginService.COOKIE_SESSION_NAME, sessionId, maxAgeInSeconds, true);
        // 核心代码
        NewCookie cookie = new NewCookie(LoginService.COOKIE_SESSION_NAME, sessionId);
        cookie.setMaxAge(maxAgeInSeconds);
        cookie.setHttpOnly(true);
        getResponse().addHeader(NewCookie.SET_COOKIE, cookie.toString());
        setAttr(LoginService.ACCT_ATTR, ret.get(LoginService.ACCT_ATTR));
        // 如果 returnUrl 存在则跳过去,否则跳去首页
        ret.set("returnUrl", getPara("returnUrl", "/"));
    }
    renderJson(ret);
}
// 注意18行,前提是不能有重复的cookie,若有Controller.setCookie相同的key(如第12行),该代码(12行)要去掉。

设置SameSite其它属性:

代码语言:javascript
复制
cookie.setSameSite(NewCookie.STRICT);

代码语言:javascript
复制
cookie.setSameSite(NewCookie.NONE).setSecure(true);

参考1:How to set the SameSite attribute in Java Web applications 注:参考1提供了更多解法,包括前端、WildFly及SpringBoot,本文只介绍Servlet相关,请自行阅读原文 参考2:应对浏览器Cookie新属性SameSite的临门一脚

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022 年 09 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引入
  • 解法1 使用Filter过滤器 推荐
  • 解法2 继承Cookie类,添加SameSite属性 不推荐
相关产品与服务
云开发 CLI 工具
云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档