在 Web 开发中,登录认证功能是保障系统安全的重要环节。登录认证的目标是:用户必须登录后才能访问系统中的功能。具体流程是用户通过登录界面提交用户名和密码,服务器验证用户信息后,生成令牌(如 JWT)并返回给前端,前端将令牌存储在本地,后续请求中携带该令牌进行验证。
1. 会话技术
1.1 会话介绍
在web开发当中,会话指的就是浏览器与服务器之间的一次连接,我们就称为一次会话。
在用户打开浏览器第一次访问服务器的时候,这个会话就建立了,直到有任何一方断开连接,此时会话就结束了。在一次会话当中,是可以包含多次请求和响应的。
需要注意的是:会话是和浏览器关联的,当有三个浏览器客户端和服务器建立了连接时,就会有三个会话。同一个浏览器在未关闭之前请求了多次服务器,这多次请求是属于同一个会话。
1.2 会话跟踪
一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
服务器会接收很多的请求,但是服务器是需要识别出这些请求是不是同一个浏览器发出来的。比 如:1和2这两个请求是不是同一个浏览器发出来的,3和5这两个请求不是同一个浏览器发出来 的。如果是同一个浏览器发出来的,就说明是同一个会话。如果是不同的浏览器发出来的,就说明 是不同的会话。而识别多次请求是否来自于同一浏览器的过程,我们就称为会话跟踪。
为什么要共享数据呢?
由于HTTP是无状态协议,在后面请求中怎么拿到前一次请求生成的数据呢?此时就需要在一次会 话的多次请求之间进行数据共享。
1.2.1 Cookie
客户端存储会话信息,自动发送到服务端。缺点是安全性较低且不能跨域。
1.2.2 Session
服务端存储会话信息,客户端通过 JSESSIONID
来标识会话。缺点是在集群环境下无法直接使用。
1.2.3 令牌(JWT)
最常用的方式,通过在登录成功后生成 JWT 令牌,并存储在前端,每次请求携带该令牌进行身份验证。优势是跨平台支持且无需在服务端存储会话状态,适合微服务和分布式系统。
2. 统一拦截技术
为了实现登录后的权限控制,需要统一拦截用户请求,检查请求中是否携带合法的 JWT 令牌。
登录校验的过滤器和拦截器,只需要使用其中的一种就可以了。
2.1 Filter过滤器
2.1.1 Filter过滤器介绍
Filter表示过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一。
过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
2.2.2 使用
第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。
第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持。
@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦
截浏览器的所有请求 )
public class DemoFilter implements Filter {
@Override //初始化方法, 只调用一次
public void init(FilterConfig filterConfig) throws
ServletException {
System.out.println("init 初始化方法执行了");
}
@Override //拦截到请求之后调用, 调用多次
public void doFilter(ServletRequest request, ServletResponse
response, FilterChain chain) throws IOException, ServletException {
System.out.println("Demo 拦截到了请求...放行前逻辑");
//放行
chain.doFilter(request,response);
}
@Override //销毁方法, 只调用一次
public void destroy() {
System.out.println("destroy 销毁方法执行了");
}
}
2.2 Interceptor拦截器
2.2.1 Interceptor拦截器介绍
是一种动态拦截方法调用的机制,类似于过滤器。
拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行。
2.2.2 使用
1. 定义拦截器
2. 注册配置拦截器
3. 登录认证功能实现
3.1 生成令牌
在登录成功之后来生成一个JWT令牌,并且把这个令牌直接返回给前端。
3.1.1 引入JWT的依赖
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
3.1.2 调用API
在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验
工具类:Jwts
public void genJwt(){
Map<String,Object> claims = new HashMap<>();
claims.put("id",1);
claims.put("username","Tom");
String jwt = Jwts.builder()
.setClaims(claims) //自定义内容(载荷)
.signWith(SignatureAlgorithm.HS256, "cytcyt") //签名算法
.setExpiration(new Date(System.currentTimeMillis() +
24*3600*1000)) //有效期
.compact();
System.out.println(jwt);
}
3.2 拦截校验令牌
拦截前端请求,从请求中获取到令牌,对令牌进行解析校验。
1. 获取请求url
2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行
3. 获取请求头中的令牌(token)
4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
5. 解析token,如果解析失败,返回错误结果(未登录)
6. 放行