会话技术
浏览器使用的是http协议,多次请求间数据是不能共享的,例如我们要去访问用户数据的接口,但这时候用户是否已经登入了呢?是不知道的,为了解决这个问题,于是引入了会话跟踪技术。
会话:用户打开浏览器,访问web资源,会话建立,知道有一方断开,会话结束。在一次会话中可以包含多次请求和响应。
会话跟踪:一种维护浏览器状态的方式,服务器需要识别多次请求是否来自同一浏览器,以便在同一次会话的多次请求间共享数据
会话跟踪方案
1.cookie
存储在浏览器 。携带的值为键值对形式name=value
浏览器第一次发起请求->服务器设置cookie,存储相关信息,例如用户名,id ->服务器自动响应数据时携带cookie->浏览器自动接收cookie并存储本地 ->后续请求将cookie自动携带到服务端->服务器判断cookie值是否存在。
优点:
- HTTP协议中支持的技术
缺点:
- 移动端APP无法使用Cookie
- 不安全,用户可以自己禁用Cookie
- Cookie不能跨域(跨域就是当前所处位置和请求地址的协议,ip,端口三着有不同的)
注意:上述中用了三个自动,这是因为cookie是HTTP协议支持的技术,请求头中有cookie,就是存储服务器之前发回来的cookie,响应头有Set-Cookie用于服务器向用户发送Cookie。
设置CookieAPI:
获取CookieAPI:
2.session
优点:
- 存储在服务器,安全
缺点:
- 服务器集群条件下无法直接使用Session
- Cookie的缺点
session 存储在服务器,底层根据Cookie实现,响应的值为JSESSIONID(固定)="SessionId"
浏览器第一次请求服务器->服务器获取session对象->服务器通过Cookie响应session id->浏览器接收session id并存储在本地->二次请求将session id携带到服务端->通过SessionId去找到对应的session会话对象
从Session对象中获取值:
在Session对象中存储值:
3.令牌技术
优点:
- 支持PC端、移动端
- 解决集群环境下的认证问题
- 减轻服务器端存储压力
令牌就是一个用户标识,就是一个字符串
用户登入请求成功->服务器生成一个令牌->响应令牌给前端,前端存储起来->前端后续请求响应令牌给服务端->服务端校验令牌有效性,共享数据可以存储在令牌当中。
下面讲解一个功能强令牌:JWT令牌
全称:JSON Web Token (https://jwt.io/)
定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。如图就是一个JWT令牌
JWT令牌由三部分组成,每部分由.隔开
- Header(头),记录令牌类型、签名算法等,由base64进行编码,例如:{"alg":"HS256","type":"JWT"}
- Payload(有效载荷),携带一些自定义信息、默认信息等,由base64进行编码 ,例如:{"id":"1","username":"Tom"}
- Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
JWT令牌生成解析:
引入依赖
使用jwts工具类进行生成令牌
0
解析令牌
当我们修改任意一部分的数据,或者令牌过期,解析都会报错
过滤器Filter
- 概念:Filter 过滤器,是JavaWeb三大组件(Servlet、Filter、Listener)之一。
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
- 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。
Filter使用:
1.定义Filter:定义一个类,实现Filter接口,并重写其所有方法。
Filter接口中有三个方法,分别是
- Init :初始化方法,default修饰,可以不用实现,web服务器启动时,创建Filter调用,只调用一次
- doFIlter:拦截到请求时调用,调用多次
- destory:服务器关闭时调用,default修饰,可以不用实现,只调用一次
2. 配置Filter:Filter类上加@WebFilter注解,通过urlPatterns属性 配置拦截资源的路径。启动类上加@ServletComponentScan开启Servlet组件支持。
拦截路径参数:
doFilter拦截到请求之后,可以通过调用chain.doFilter(request,response); 来放行访问资源。只有放行了才能访问到资源。访问完资源之后又会回到doFilter方法执行chain.doFilter方法之后的代码
过滤器链:
一个Web应用中,可以配置多个过滤器,多个过滤器就形成了过滤器链
过滤器链中的过滤器会逐渐一个个放行,先调用放行前的逻辑,然后放行到下一个过滤器,到资源访问之后会从最后一个过滤器放行后的逻辑逐渐往前一个过滤器执行。过滤器的排序根据类名大小排序
现在我们来尝试一下写好登入校验过滤器的代码,我们先来分析一下
1.获取前端的访问路径
2.查看是否是登录路径如果是登录路径,直接放行,并将方法结束
3.获取请求头中的令牌
4.校验令牌,解析如果不存在返回错误信息
5.令牌解析错误返回错误信息
6.放行
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOEx
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//1.获取请求ur1。
String url = req.getRequestURL () . toString () ;
log.info("请求的url:{}",url);
//2.判断请求ur1中是否包含login,如果包含,说明是登录操作,放行。
if (url.contains ("login") ) {
log.info("登录操作,放行 ….. ");
chain.doFilter (request, response) ;
return;
}
//3.获取请求头中的令牌(token)。
String jwt = req.getHeader ( name: "token") ;
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
if (!StringUtils. hasLength (jwt) ) {
log.info(“请求头token为空,返回未登录的信息”);
Result error = Result.error("NOT_LOGIN");
//手动转换 对象 -- json
String notLogin = JSONObject.toJSONString(error) ;
resp.getWriter().write (notLogin) ;
return;
}
阿里巴巴fastJSON
-- >
//5.解析token,如果解析失败,返回错误结果(未登录)。
try {
JwtUtils.parseJWT(jwt) ;
}catch(Exception e){//jwt解析失败
e.printStackTrace () ;
log.info(“解析令牌失败,返回未登录错误信息”);
Result error = Result.error("NOT_LOGIN");
//手动转换 对象 -- json
String notLogin = JSONObject.toJSONString(error) ;
resp.getWriter().write (notLogin) ;
return;
//6.放行。
log.info("令牌合法,放行");
chain.doFilter (request, response) ;
}
拦截器Interceptor
概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。
作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
使用:
1.定义拦截器,实现HandlerInterceptor接口,接口中实现了三个方法
分别在不同时期执行,并将其交给IOC容器
2.定义配置类,实现接口WebMvcConfigurer,并加上@Configuration注解表明是Spring中的配置类,然后通过重写addInterceptors方法,调用registry的addIntercepto方法来注册拦截器
3.然后通过addPathPatterns方法来配置拦截的资源也可以通过excludePathpatterns来配置不拦截的资源
执行流程:
浏览器访问Web应用->过滤器拦截前逻辑->过滤器放行->进入Spring的环境,tomcat不识别Spring的Controller程序,但识别Servelet,Spring环境提供了一个核心的Serelet:DispatcherServelet。他把请求转给拦截器->拦截器先执行preHandle方法如果放行,访问Controller方法->执行拦截器的postHandle和afterCompletion方法->返回给DispathcherServelet->执行拦截器放行后的代码
Filter和Interceptor区别:
- 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现Handlerlnterceptor接口。
- 拦截范围不同: 过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。