登陆检验

登陆检验

登陆检验:在每次发送访问网页请求时进行一个登陆检验,检验用户是否登陆

会话技术

  • 会话: 用户打开浏览器,访问web服务器的资源,会话建立,有一方断开连接,会话就会结束。在一次会话中会包含多次请求和响应

  • 会话跟踪: 服务器需要识别多次请求是否来自于同一浏览器,以便在多次请求间共享数据

  • 会话跟踪方案:

    • 客户端会话跟踪:Cookie
    • 服务端会话跟踪:Session
    • 令牌技术

alt text

JWT令牌

  • JWT令牌:Json Web Token
  • 一种简洁的、自包含的格式,用于通信双方以json格式安全得传输信息。由于数字签名的存在,这些信息是可靠的。

JWT 组成
包括 Header、Payload、Signature 三部分

alt text

  • 头部和有效载荷:对原始json格式数据进行 Base64的 编码得到 新的字符串
  • 数字签名 是通过签名算法 加密得到

alt text

JWT令牌进行登陆认证

流程:

  1. 登陆成功,生成令牌
  2. 每次发起请求时,都要携带令牌,服务器处理请求时,先校验令牌,通过后,再处理

生成JWT令牌

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
26
27
28
29
30
public class JjwtTest {
@Test
public void generateToken() {
// JWT头部分信息【Header】
Map<String, Object> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");

// 载核【Payload】
Map<String, Object> payload = new HashMap<>();
payload.put("sub", "1234567890");
payload.put("name","John Doe");
payload.put("admin",true);

// 声明Token失效时间
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,300);// 300s

// 生成Token
String token = Jwts.builder()
.setHeader(header)// 设置Header
.setClaims(payload) // 设置载核
.setExpiration(instance.getTime())// 设置生效时间
.signWith(SignatureAlgorithm.HS256,"secret") // 签名,这里采用私钥进行签名,不要泄露了自己的私钥信息
.compact(); // 压缩生成xxx.xxx.xxx

System.out.println(token);
}
}

解析jwt令牌

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
26
27
28
29
30
31
32
@Test
public void getInfoByJwt() {
// 生成的token
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTY2MzI5NzQzMX0.Ju5EzKBpUnuIRhDG1SU0NwMGsd9Jl_8YBcMM6PB2C20";
// 解析head信息
JwsHeader jwsHeader = Jwts
.parser()
.setSigningKey("secret")
.parseClaimsJws(token)
.getHeader();

System.out.println(jwsHeader); // {typ=JWT, alg=HS256}
System.out.println("typ:"+jwsHeader.get("typ"));

// 解析Payload
Claims claims = Jwts
.parser()
.setSigningKey("secret")
.parseClaimsJws(token)
.getBody();
System.out.println(claims);// {sub=1234567890, name=John Doe, admin=true, exp=1663297431}
System.out.println("admin:"+claims.get("admin"));

// 解析Signature
String signature = Jwts
.parser()
.setSigningKey("secret")
.parseClaimsJws(token)
.getSignature();
System.out.println(signature); // Ju5EzKBpUnuIRhDG1SU0NwMGsd9Jl_8YBcMM6PB2C20
}

JWT工具类

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
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.cslb.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.ibatis.type.NStringTypeHandler;

import javax.xml.crypto.Data;
import java.util.Date;
import java.util.Map;

public class JwtUtils {

private static String signkey = "cslb";

/**
* 生成JWT令牌
* @param claims jwt第二部分载荷存储的内容
* @return
*/
public static String generateJwt(Map<String,Object> claims) {
String jwt = Jwts.builder()
.addClaims(claims) //添加载荷
.signWith(SignatureAlgorithm.HS256,signkey) //设置签名算法和密钥
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)) //设置失效时间为1小时
.compact();
return jwt;
}

public static Claims parseJwt(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(signkey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}

过滤器 Filter

对url请求进行拦截,决定是否放行

Filter 的快速创建流程:

  1. 实现Filter接口
  2. 配置:
  • @WebFilter(urlPatterns = "/*") (拦截的url请求参数)
  • @ServletComponentScan (在springboot项目中开启Servlet组件支持)

过滤器链

在一个web应用中,可以配置多个过滤器,多个过滤器形成了一个过滤器链

过滤器链的执行过程
请求 -> 放行前的逻辑 -> 放行 - > 访问资源 -> 放行后的逻辑

alt text

对于由注解配置的多个过滤器,其执行顺序是按照过滤器类名的字典序进行排列

拦截器 Interceptor

过滤器和拦截器整体的执行流程
alt text

过滤器和拦截器区别

  • 所需要实现的接口不同,(Filter / HandlerInterceptor)
  • 拦截范围不同,Filter 会拦截所有资源,Interceptor只会拦截Spring环境中的资源

登陆检验
https://cs-lb.github.io/2024/10/28/Java/登陆检验/
作者
Liu Bo
发布于
2024年10月28日
许可协议