Loading... ### 引入 最近学习了Servlet、Mybatis、Vue,想手搓一个用户登录界面+数据展示后台,但是在记住用户登录 设置cookie的时候遇到的问题。问题是:使用 `HttpServletResponse` 的 `addCookie()` 方法后,开发者工具提示 `某些 Cookie 滥用推荐的"sameSite"属性 由于 Cookie 的"sameSite"属性设置为"none",但缺少"secure"属性,此 Cookie 未来将被拒绝。` ### 解法1 使用Filter过滤器 推荐 创建一个Filter类,重写doFilter方法 ```java 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属性 不推荐 ```java 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代码: ```java /** * 登录 */ @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其它属性: ``` cookie.setSameSite(NewCookie.STRICT); ``` 或 ``` cookie.setSameSite(NewCookie.NONE).setSecure(true); ``` <br> <br> 参考1:[How to set the SameSite attribute in Java Web applications](http://www.mastertheboss.com/web/jboss-web-server/how-to-set-the-samesite-attribute-in-java-web-applications/) 注:参考1提供了更多解法,包括前端、WildFly及SpringBoot,本文只介绍Servlet相关,请自行阅读原文 参考2:[应对浏览器Cookie新属性SameSite的临门一脚](https://jfinal.com/share/2136) 最后修改:2022 年 09 月 17 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 3 本作品采用 CC BY-NC-SA 4.0 International License 进行许可。