Springboot+JWT

1.什么是JWT

JWT(JSON WEB TOKEN)是一种标准,用来在前后端或者系统间以JSON对象安全的传输信息,该信息是可以被验证和信任的,因为它是数字签名的。可以使用HMAC或RSA或ECDSA的公钥/私钥进行签名。

2.JWT能做什么

  1. 授权
    一旦登录,每个后续请求都包括JWT,用户就可以访问该令牌允许的路由、服务和资源
  2. 信息交换
    可以对JWT签名,确保收件人是对的人,还可以验证内容是否篡改

3.为什么用JWT

3.1 传统登录基于session认证

在这里插入图片描述

  1. 如何实现的
    • 客户端发送账号密码到后端
    • 账号密码验证通过,用户登录成功以后,返回一个sessionId给客户端,客户端每次请求时候,都携带这个sessionId,就表示它已经登陆过了,不需要再输入用户名密码。
  2. 存在问题
    • 每个用户都要在服务端保存一个sessionId来保存它的登录状态,一般session都是保存在内存中,用户越多,服务器压力越大。
    • 用户认证之后,如果session存在对应服务器的内存中,下次用户访问必须还是这台服务器,但是现在分布式的应用,负载均衡后没法确定是访问哪台服务器。
    • 基于cookie来识别用户,如果被篡改,容易收到跨站请求伪造攻击

3.2 基于JWT认证

  1. 如何实现的
    • 客户端发送账号密码到后端,
    • 账号密码验证通过后,将用户的id等其他信息作为Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(token),格式如xxx.xxx.xxx,由.分割,三部分组成head,payload,singurater
    • 客户端接收到JWT后保存在本地,退出登录时,就删除本地的JWT
    • 前端每次请求将JWT放在HTTP Header的Atuthorization中,解决XSS和XSRF。
    • 后端收到请求,就验证JWT的有效性,是否过期,签名是否正确等。
    • 验证通过后,后端使用JWT中包含的用户信息进行对应操作。
  2. 优势
    • 可以通过URL、post参数或header发送,数据量小,传输速度快。
    • 负载中包含了用户信息,避免多次查询数据库
    • token以JSON加密的形式保存在客户端,所以可以跨语言,原则上任何web形式都支持。
    • 不保存在服务端,适合分布式微服务。

4.JWT的结构

令牌的组成

  • 标头(Header)
  • 有效载荷(Payload)
  • 签名(Signature)

格式如xxx.xxx.xxx,由.分割,三部分组成

4.1 Header

标头,标头通常由两部分组成,令牌的类型(JWT)和所使用的签名算法,例如HMAC、SHA256或RAS。

明文信息,json字符串

{
   
   
	"alg":"HS256",
	"typ":"JWT"
}

使用Base64编译为 xxx 这种格式,作为JWT的第一部分

4.2 Payload

有效负载,其中包含声明,声明是有关信息,也会使用Base64转为xxx,作为JWT的第二部分

{
   
   
	"id":"sad854dsfewr1",
	"name":"zhangsan"
}

需要注意的是,不要在这里放入敏感信息,例如密码,因为Base64是可逆的

4.3 Signature

签名,对头部及负载内容进行签名,保证JWT没有被篡改

5.JWT的使用

  • 引入依赖

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>
    
  • 创建令牌

        @Test
        void contextLoads() {
         
         
            String secretKey="asdf1213$1f.sad";     //密钥
    
            //设置时间20s
            Calendar instance = Calendar.getInstance();
            instance.add(Calendar.SECOND,20);
    
            String token = JWT.create()
                    //.withHeader(map)      不设置头的话,默认就是alg:HMAC256  typ:JWT
                    .withClaim("id", "asd123456")   //设置id
                    .withClaim("name", "zhangsan")  //设置用户名
                    .withExpiresAt(instance.getTime())  //设置过期时间
                    .sign(Algorithm.HMAC256(secretKey));//使用密钥设置签名
    
            System.out.println(token);
        }
    

    输出结果eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiemhhbmdzYW4iLCJpZCI6ImFzZDEyMzQ1NiIsImV4cCI6MTY5Nzc2OTMxNn0.MwxzzpvvCmCXB6JYWWVsMnRffo4RkpW413aDRndkbCc

  • 验证令牌
    这里密钥要和加密的密钥一致,否则签名验证不通过

    @Test
    void test(){
         
         
        String secretKey="asdf1213$1f.sad";     //密钥
    
        //创建验证对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secretKey)).build();
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiemhhbmdzYW4iLCJleHAiOjE2OTc3NzEyMTB9.Ro9YSdTmuqdrisQhXRVDxPT-pv4FZLb5nnQkNRUrMjc");
        //获取负载中name的值,存什么类型的值,就要使用对应的asInt或者asString
        System.out.println(verify.getClaim("name").asString());
        //获取过期时间
        System.out.println(verify.getExpiresAt());
    
    }
    
  • 常见异常
    在这里插入图片描述

    • SignatureVerificationException 签名不一致
    • TokenExpiredException 令牌过期
    • AlgorithmMismatchException 算法不匹配
    • InvalidClaimException 失效的payload

6.封装JWT工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

public class JWTUtils {
   
   

    //密钥
    private static final String SECRET_KEY = "asdf1213$1f.sad";

    /**
     * 生成token
     * @param map   负载中存储的值
     * @return  生成的token值
     */
    public static String getToken(Map<String, String> map) {
   
   

        //设置过期时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, 7);  //默认7天

        //创建JWT builder
        JWTCreator.Builder builder = JWT
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值