会话技术
会话:
用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束.在一次会话中包含多次请求和响应
会话跟踪:
一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一个浏览器,以便在同一次会话的多次请求之间共享数据
会话跟踪方案:
客户端会话跟踪技术: Cookie
服务端会话跟踪技术: Session
令牌技术
会话跟踪方案的对比:
Cookie:
优点: HTTP协议中支持的技术
请求的时候(Cookie:name=value)
响应的时候 (Set-Cookie: name=value)
设置Cookie:
// 这里的response 是 HttpServletResponse类的
response.addCookie(new Cookie("CookieName", "CookieValue"));
获取Cookie:
// 这里的request 来自于HttpServletRequest
Cookie[] cookies = request.getCookies(); // 获取所有的Cookie
// 遍历的时候 可以用foreach进行遍历
for(Cookie cookie : cookies)
缺点:
移动端APP无法使用Cookie
不安全,用户可以自己禁用Cookie
Cookie不能跨域
Session:
优点:储存在服务器端,安全
缺点:服务器集群环境下无法直接使用Session, 以及Cookie的缺点,因为Session的底层是基于Cookie实现的
往HttpSession中存储数据:
// session 是来自于HttpSession类里面的
session.setAttribute("name", "value"); // 往session中存储数据
从HttpSession中获取值:
// 这里的 request是来自于HttpServletRequest类里面的
HttpSession session = request.getSession();
Object t = session.getAttribute("name"); // 从session中获取数据
令牌技术(JWT):
优点: 支持pc端,移动端,解决集群环境下的认证问题,减轻服务器端存储压力
缺点:需要自己实现
简介:(JSON Web Token)
JWT以json数据格式安全的传输信息
组成:
第一部分:Header(头), 记录令牌类型, 签名算法
第二部分:Payload(有效载荷), 携带一些自定义信息 默认信息等
第三部分: Signature(签名), 防止Token被篡改,确保安全性, 将header payload 并加入指定密钥,通过指定签名算法计算而来
生成:
先引入依赖:
设置 拿到jwt令牌
Map<String, Object> claims = new HashMao<>();
claims.put("id", 1);
claims.put("name", "Tom");
String jwt = Jwts.builder()
//第一个参数是用的是什么算法 第二个参数是你自定义的密钥
.signWith(SignatureAlgorithm.HS256, "FindYou");
.setClaims(claims); // 自定义内容(载荷)
// 下面这个设置的有效期是1小时后 注意是参数的单位是毫秒值
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)); //设置有效期
.compact();
解析:
解析过期的令牌会发生异常
Claims claims = Jwts.parser()
.setSigningKey("FindYou") // 这个是你之前设置的密钥
.parseClaimsJws("这里传的是你之前获得的jwt令牌 也就是一串字符串")
.getBody(); // 获得第二部分 也就是存储的对象信息
注意事项:
过滤器(Filter)
概述:
代码演示:d
@WebFilter(urlPatterns = "/*") // 拦截的url
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截到了");
filterChain.doFilter(servletRequest, servletResponse); // 放行
}
}
在登录校验中 过滤器的用法思路:
代码:
@Slf4j
@WebFilter(urlPatterns = "/*") // 拦截的url
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
// 获取请求的url
String url = req.getRequestURL().toString();
log.info("请求的url = {}", url);
//判断url之中 是否有login 要是包含的话 直接放行
if(url.contains("login")) {
filterChain.doFilter(servletRequest, servletResponse); // 放行
return;
}
// 获取请求头中的令牌
String jwt = req.getHeader("token"); // 拿到令牌
if(!StringUtils.hasLength(jwt)) { // 这样为空 或者是为null 就返回错误的信息
log.info("请求头token为空");
Result error = Result.error("NOT_LOGIN");
// 将对象转换为json的数据
String notLogin = JSONObject.toJSONString(error);// 转换为json格式的字符串
resp.getWriter().write(notLogin); // 响应给浏览器
return;
}
//解析token
try {
JwtsUtils.parseJWT(jwt);
}catch (Exception e) { // 解析失败
e.printStackTrace();
log.info("解析令牌失败 返回未登录错误信息");
Result error = Result.error("NOT_LOGIN");
// 将对象转换为json的数据
String notLogin = JSONObject.toJSONString(error);// 转换为json格式的字符串
resp.getWriter().write(notLogin); // 响应给浏览器
return;
}
// 放行
filterChain.doFilter(servletRequest, servletResponse);
}
}