JWT和token介绍

JWT和token介绍

什么是 Token?Token 是一种由服务器生成的字符串,通常用于标识用户的身份或会话状态。它可以在客户端和服务器之间传递,用于验证用户的身份或授权用户访问特定资源。

Token 的用途Token 的主要用途包括:

身份验证(Authentication):验证用户是否是他们声称的那个人。例如,用户登录时,服务器会生成一个 Token 并发送给客户端,客户端在后续请求中携带这个 Token,服务器通过验证 Token 来确认用户身份。
授权(Authorization):决定用户是否有权限访问某个资源。例如,某些 API 可能需要特定的 Token 才能访问。
会话管理(Session Management):在无状态的 HTTP 协议中,Token 可以用来跟踪用户的会话状态。
数据传输:Token 可以携带一些用户信息(如用户 ID、角色等),方便在请求中传递这些信息,而无需每次都查询数据库。
在这里插入图片描述

常见的 Token 类型

JWT(JSON Web Token)

定义:JWT 是一种开放标准(RFC 7519),用于在各方之间安全地传递信息。JWT 的信息可以被验证和信任,因为它是数字签名的。• 结构:JWT 由三部分组成,用点( . )分隔:

  • Header(头部):通常包含令牌的类型(如 JWT)和使用的签名算法(如 HS256)。
  • Payload(载荷):包含声明(Claims),这些声明是关于实体(通常是用户)和其他数据的声明。例如:
  • sub (Subject):主题,通常是用户的唯一标识。
  • exp (Expiration Time):过期时间。
  • iat (Issued At):签发时间。• 自定义声明:如用户 ID、角色等。
  • Signature(签名):用于验证消息的完整性和确保消息是由可信方发送的。
  • 优点:
  1. 无状态:JWT 是自包含的,服务器不需要存储会话信息。
  2. 可扩展:可以携带用户信息,减少数据库查询。
  3. 跨域:可以跨不同的系统和平台使用。
  • 缺点:
  1. 安全性:如果 Token 被泄露,攻击者可以伪造请求。因此,Token 必须通过 HTTPS 传输。
  2. 大小:JWT 可能比较大,不适合存储大量数据。
    在这里插入图片描述

springBoot整合JWT实例:

package com.nie.utils;

import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.Date;

@Data
@Component
@ConfigurationProperties(prefix = "jwt.token")
public class JwtHelper {
    // JWT 令牌的有效时间,单位为毫秒(1000毫秒 = 1秒)
    private long tokenExpiration;

    // JWT 签名密钥,用于生成和验证 JWT 令牌
    private String tokenSignKey;

    /**
     * 生成 JWT 令牌字符串。
     * 这个方法根据用户 ID 创建一个 JWT 令牌,并设置其有效时间和签名。
     *
     * @param userId 用户的唯一标识
     * @return 生成的 JWT 令牌字符串
     */
    public String createToken(Long userId) {
        System.out.println("tokenExpiration = " + tokenExpiration);
        System.out.println("tokenSignKey = " + tokenSignKey);
        String token = Jwts.builder()
                .setSubject("YYGH-USER") // 设置主题(可以是任意字符串,用于标识令牌的用途)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration * 1000 * 60)) // 设置令牌的有效时间(单位为分钟)
                .claim("userId", userId) // 添加用户 ID 到 JWT 的自定义声明中
                .signWith(SignatureAlgorithm.HS512, tokenSignKey) // 使用 HS512 算法和签名密钥对令牌进行签名
                .compressWith(CompressionCodecs.GZIP) // 对 JWT 令牌进行压缩
                .compact(); // 将 JWT 令牌转换为紧凑的字符串形式
        return token;
    }

    /**
     * 从 JWT 令牌字符串中获取用户 ID。
     * 这个方法解析 JWT 令牌,并从其自定义声明中提取用户 ID。
     *
     * @param token JWT 令牌字符串
     * @return 用户 ID,如果令牌无效或为空,则返回 null
     */
    public Long getUserId(String token) {
        if (StringUtils.isEmpty(token)) return null; // 如果令牌为空,直接返回 null
        Jws<Claims> claimsJws = Jwts.parser() // 解析 JWT 令牌
                .setSigningKey(tokenSignKey) // 设置签名密钥
                .parseClaimsJws(token); // 解析并验证 JWT 令牌
        Claims claims = claimsJws.getBody(); // 获取 JWT 的声明部分
        Integer userId = (Integer) claims.get("userId"); // 从声明中提取用户 ID
        return userId.longValue(); // 返回用户 ID 的长整型值
    }

    /**
     * 判断 JWT 令牌是否过期。
     * 这个方法解析 JWT 令牌,并检查其有效时间是否已经过期。
     *
     * @param token JWT 令牌字符串
     * @return 如果令牌过期或无效,返回 true;否则返回 false
     */
    public boolean isExpiration(String token) {
        try {
            boolean isExpire = Jwts.parser() // 解析 JWT 令牌
                    .setSigningKey(tokenSignKey) // 设置签名密钥
                    .parseClaimsJws(token) // 解析并验证 JWT 令牌
                    .getBody() // 获取 JWT 的声明部分
                    .getExpiration() // 获取令牌的有效时间
                    .before(new Date()); // 检查有效时间是否在当前时间之前
            // 如果没有过期,返回 false
            return isExpire;
        } catch (Exception e) {
            // 如果解析失败或令牌过期,返回 true
            return true;
        }
    }
}

package com.nie.interceptors;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nie.utils.JwtHelper;
import com.nie.utils.Result;
import com.nie.utils.ResultCodeEnum;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class LoginProtectedInterceptor implements HandlerInterceptor {
    // 自动注入 JwtHelper 工具类,用于处理 JWT 相关的逻辑
    @Autowired
    private JwtHelper jwtHelper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头中获取名为 "token" 的值
        String token = request.getHeader("token");

        // 调用 JwtHelper 的 isExpiration 方法,检查 token 是否过期
        boolean expiration = jwtHelper.isExpiration(token);

        // 如果 token 未过期,允许请求继续执行
        if (!expiration) {
            return true;
        }

        // 如果 token 过期或无效,创建一个未登录的提示结果
        Result result = Result.build(null, ResultCodeEnum.NOTLOGIN);

        // 创建 ObjectMapper 对象,用于将 Result 对象转换为 JSON 格式的字符串
        ObjectMapper objectMapper = new ObjectMapper();

        // 将 Result 对象转换为 JSON 格式的字符串
        String json = objectMapper.writeValueAsString(result);

        // 将 JSON 字符串写入响应体,返回给客户端
        response.getWriter().print(json);

        // 返回 false,表示拦截请求,阻止请求继续执行
        return false;
    }
}

package com.nie.config;

import com.nie.interceptors.LoginProtectedInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginProtectedInterceptor loginProtectedInterceptor;
    @Override
    /**
     *
     *添加拦截器
     */
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginProtectedInterceptor).addPathPatterns("/headline/**");
    }
}

#jwt配置
jwt:
  token:
    tokenExpiration: 120 #有效时间,单位分钟
    tokenSignKey: headline123456  #当前程序签名秘钥 自定义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值