jwt和token区别

一、安全性比较‌

  1. ‌验证方式‌:

    • Token:服务端验证客户端发送的Token时,通常需要查询数据库获取用户信息,以验证Token的有效性。‌
    • JWT(JSON Web Token):服务端验证JWT时,只需使用密钥解密进行校验,无需查询或减少查询数据库,因为JWT自包含了用户信息和加密的数据。
  2. ‌信息安全性‌:

    • Token:一般的Token没有签名机制,只能通过验证Token的合法性来确保安全性,可能存在被伪造的风险。‌
    • JWT:使用签名来验证Token的有效性,确保Token在传输过程中没有被篡改,因此更安全。‌

二、实际应用中的区别‌

  1. ‌存储位置与信息包含‌:

    • Token:通常只是一个标识符,需要在服务器上存储相关的用户信息。‌
    • JWT:包含了所有必要的信息,如用户信息、加密信息和过期时间,服务端不需要保存任何用户信息。‌
  2. ‌格式与结构‌:

    • Token:结构多样,可以是简单的字符串、Base64编码的字符串等,没有固定的格式要求。‌1
    • JWT:遵循RFC 7519标准,由头部(Header)、载体(Payload)和签名(Signature)三部分组成,使用JSON对象来存储信息,并使用Base64编码进行传输。‌
  3. ‌无状态性‌:

    • Token:需要在服务端存储相关信息,增加了服务端的负担。‌5
    • JWT:是无状态的,服务端不需要保存任何用户信息,只需验证JWT的签名即可。‌
  4. ‌扩展性‌:

    • Token:通常只能存储有限的信息。
    • JWT:可以存储更多的信息,如用户的角色、权限等。

JWT 格式

使用逗号分隔的三部分 :

    • Header
    • Payload
    • Signature
      token 格式:xxxxx.yyyyy.zzzzz

Header 通常由 token 类型和签名算法名两部分组成.是token的第1部分
例如:

  {
  "alg": "HS256", // 签名算法
  "typ": "JWT" // token类型
  }
         然后, 这个JSON 使用 Base64Url 编码后放到 JWT 的第1部分.

2、Payload

Payload 是token的第2部分.包含了一些声明(claims).声明的名字必须是唯一的.

payload 示例

  {
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
  }

JSON 

然后, 这个JSON 使用 Base64Url 编码后放到 JWT 的第2部分.

3、Signature
拿到编码后的 header 和 编码后的 payload 使用 密码进行签名.

使用 HMAC SHA256 加签示例:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
 Signature需要使用编码后的header和payload以及我们提供的一个秘钥,然后使用header中指定的签名算法进行签名,签名的作用是保证JWT没有被篡改过

HMACSHA256(base64UrlEncode(header)+“.”+base64UrlEncode(payload),secret)

secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。【secret 是签名秘钥】

 

 

4、 JWT实现:
1、依赖引入

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt-jsonwebtoken.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>RELEASE</version>
</dependency>
2、生成Token

// 签名密钥
private static final String SECRET = "!Doker$";
public String createToken(Map<String, Object> claims, String subject) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, Algorithm.HMAC256(SECRET))
.compact();
}

private Date calculateExpirationDate(Date createdDate) {
return new Date(createdDate.getTime() + expiration * 1000);
}
3、刷新Token

public String RefreshToken(String token) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
final Claims claims = getAllClaimsFromToken(token);
claims.setIssuedAt(createdDate);
claims.setExpiration(expirationDate);
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, Secret)
.compact();
}
4、token发送给前端
传入当前用户的功能与用户信息,登录名生成token,写入response的返回头中,前端获取后保存在前端的本地缓存中,后续前端请求要把token放在头header里。

 

//登录成功之后
List<Object> functs=(List<Object>) authResult.getAuthorities();
//当前功能列表
String loginName=authResult.getName();//登录名
Users obj=(Users)authResult.getPrincipal();//用户信息
String token=JwtUtil.createToken(loginName,functs,obj);

//生成token TOKEN_HEADER= Authorization TOKEN_PREFIX=Bearer token值
response.setHeader(JwtUtil.TOKEN_HEADER,JwtUtil.TOKEN_PREFIX+token);
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK); //个人编写的视图对象
DTO dto=new DTO<>();
dto.setCode("000000");
dto.setMessage("认证通过");

PrintWriter pw=response.getWriter();
pw.write(JsonUtil.set(dto));//写入json
pw.flush();//强制刷新
pw.close();//关闭流
 

5、验证用户请求携带token

String header = request.getHeader(JwtUtil.TOKEN_HEADER);
if (null == header || !header.toLowerCase().startsWith(JwtUtil.TOKEN_PREFIX)) {
// 如果头部 Authorization 未设置或者不是 basic 认证头部,则当前
// 请求不是该过滤器关注的对象,直接放行,继续filter chain 的执行
chain.doFilter(request, response);
return;
}

try {
String token = header.replace(JwtUtil.TOKEN_PREFIX, "");
// 验证token是否过期
if (JwtUtil.isExpiration(token)) {
throw new javax.security.sasl.AuthenticationException("token 验证不通过");
}

//檢查token是否能解析
Users user = (Users) JwtUtil.getUser(token);
if (null == user) {
throw new javax.security.sasl.AuthenticationException("token 验证不通过");
}

//验证成功
 

posted @ 2025-03-26 14:16  KLAPT  阅读(671)  评论(0)    收藏  举报