Java中的会话,过滤与拦截
会话技术
Cookie
Cookie技术有三个自动:
- 服务器会 自动 的将 cookie 响应给浏览器。
- 浏览器接收到响应回来的数据之后,会 自动 的将 cookie 存储在浏览器本地。
- 在后续的请求当中,浏览器会 自动 的将 cookie 携带到服务器端。
Cookie的使用:
设置Cookie 服务端 ——> 浏览器
关键: 形参包含 HttpServletResponse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CookieController {
// 1. 设置 Cookie
public String setCookie(HttpServletResponse response) {
// 创建一个 Cookie 对象
Cookie cookie = new Cookie("user_token", "abc123");
// 可选:配置 Cookie 属性
cookie.setPath("/"); // 作用路径(默认当前路径)
cookie.setMaxAge(24 * 60 * 60); // 有效期 1 天(单位:秒)
cookie.setHttpOnly(true); // 禁止 JS 访问(防 XSS)
cookie.setSecure(false); // 非 HTTPS 时设为 false(本地测试用)
// 将 Cookie 添加到响应中
response.addCookie(cookie);
return "Cookie 设置成功!";
}
}读取/删除Cookie 浏览器——>服务端
依旧使用 HttpServletRequest:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public String readCookie2(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("user_token".equals(cookie.getName())) {
return "获取到的 Cookie 值: " + cookie.getValue();
}
}
}
return "Cookie 不存在或已过期!";
}
// 3. 删除 Cookie
public String deleteCookie(HttpServletResponse response) {
// 创建一个同名的空 Cookie,并设置 MaxAge=0
Cookie cookie = new Cookie("user_token", "");
cookie.setPath("/");
cookie.setMaxAge(0); // 立即过期
response.addCookie(cookie);
return "Cookie 已删除!";
}
Session
设置Session数据
HttpServletRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SessionController {
public String setSession(HttpServletRequest request) {
// 获取当前 Session(如果不存在则自动创建)
HttpSession session = request.getSession();
// 向 Session 中存储数据
session.setAttribute("user", "Alice");
session.setAttribute("role", "admin");
return "Session 数据已设置!";
}
}读取Session数据
依旧HttpServletRequest,读写不同之处仅为 getAttribute 和 setAttribute
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public String getSession(HttpServletRequest request) {
HttpSession session = request.getSession(false); // 如果不存在,返回 null
if (session == null) {
return "Session 不存在或已过期!";
}
String user = (String) session.getAttribute("user");
String role = (String) session.getAttribute("role");
return String.format("Session 数据: user=%s, role=%s", user, role);
}
public String invalidateSession(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate(); // 立即销毁 Session
return "Session 已销毁!";
}
return "Session 不存在!";
}
令牌
三部分组成
- 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:”HS256”,”type”:”JWT”}
- 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:”1”,”username”:”Tom”}
- 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
自定义JWT获取/解析类
加密JWT的四个链式调用步骤:
- Jwts.builder().signWith(加密算法,人为给出加密字符串)
- .addClaims(传入要加密的map集合)
- .setExpiration(Date对象,规定过期时间)
- .compact(); 最终打包
解密的四步链式调用:
Jwts.parser()
.setSigningKey(加密时指定的加密字符串)
.parseClaimsJws(加密后的字符串)
.getBody()
——> 用map接收
1 | public class JwtUtils { |
各种会话技术的深度理解(核心)
Q:Cookie和Session本质上的区别和联系是什么
A:从形态上讲,Cookie可以理解为一个容器,Session方案是一种变种Cookie,
原来的Cookie是直接存放键值对数据,这导致数据会直接存在浏览器端,可能会产生不安全问题
而Session方案本质上也是使用Cookie,只是在Cookie中只存了一个SessionId,真正的信息需要到服务端凭借Id去取
Q:Cookie和Jwt方案的区别和联系是什么,换句话说,Cookie和Jwt所用到的核心内容载体“Token”有啥区别
A:Cookie和Token都是Http请求头中的一个字段,不同的是,
Cookie是一种已经被定义好的,不管是浏览器端还是服务端,都有对其相应的使用规范的一个字段
Token是一个自定义字段,Token只是约定俗成的名字,可以改成Auth,可以改成myCookie,只要前后端约定好就行
Token在Jwt中的角色作用,既可以是传递原来存在Cookie中的具体的值,也可以是模仿Session方案传递Id用来标识用户等,因为反正都会被加密
Q:Reddis方案相比于其他方案有什么区别和联系
A:Redis方案,是把数据存放到Redis中,在用户登录校验的场景中,存放的可以是整个用户对象(包含用户的id),
使用Redis方案也要用到自定义的Token,用来传递用户标识,然后拿来当作key去redis里面取
A2:Redis方案和Jwt方案还解决了分布式多Tomcat服务器下,Session方案由于自带SessionId只能在同一个tomcat服务器流通而产生的一个问题:
用redis实现登录和用户信息的传递,和使用jwt实现登录以及用户信息传递,都是本质上通过自定义token来进行用户的唯一标识,解决了基于session时,使用自带的sessionid作为唯一标识导致多tomcat服务器时的不兼容问题
过滤器
Filter表示过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一,也是现在web开发中唯一有一个还在用的
Filter的使用:
- 第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。
- 第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持
1 | //2.1配置拦截路径 |
具体实现:
核心有三点:
- 把参数中的 ServletRequest 和 ServletRequest 强转成HttpServletRequest 和 HttpServletResponse,从request中获取路径信息,token信息
- 放行调用chain.doFilter方法,参数是request和response,这俩本来就是要传的,所以相当于放行了
- chain.deFilter放行以后,会等相关所有方法都执行完,在回到他的下一条语句进行执行
1 |
|
| 拦截路径 | urlPatterns值 | 含义 |
|---|---|---|
| 拦截具体路径 | /login | 只有访问 /login 路径时,才会被拦截 |
| 目录拦截 | /emps/* | 访问/emps下的所有资源,都会被拦截 |
| 拦截所有 | /* | 访问所有资源,都会被拦截 |
过滤器链
过滤器链上过滤器的执行顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序。 比如:
AbcFilter DemoFilter
这两个过滤器来说,AbcFilter 会先执行,DemoFilter会后执行,访问完web资源之后,还会回到过滤器当中来执行过滤器放行后的逻辑,而在执行放行后的逻辑的时候,顺序是反着的
拦截器
拦截器是SpringBoot提供的
使用拦截器
定义拦截器 ——> 实现HandlerInterceptor接口,并重写其所有方法
使用拦截器 ——> 创建一个配置类实现 WebMvcConfigurer 接口,并重写 addInterceptors 方法
在方法中,将拦截器对象通过 addInterceptor 方法 传入 registry ,链式调用 addPathPatterns 方法指定拦截路径
1 | //自定义拦截器 |
1 | //加注解 |
拦截路径自定义:通过 addPathPatterns 和 excludePathPatterns 方法

拦截器拦截路径:
| 拦截路径 | 含义 | 举例 |
|---|---|---|
| /* | 一级路径 | 能匹配/depts,/emps,/login,不能匹配 /depts/1 |
| /** | 任意级路径 | 能匹配/depts,/depts/1,/depts/1/2 |
| /depts/* | /depts下的一级路径 | 能匹配/depts/1,不能匹配/depts/1/2,/depts |
| /depts/** | /depts下的任意级路径 | 能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1 |


