Jwt教程以及SpringBoot整合Jwt

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

前言

一、使用场景

二、使用步骤

           Jwt结构

前言

学习Jwt,那么Jwt是用来做什么的呢,Jwt又是什么呢?

        Jwt的作用:从而允许用户访问该令牌允许的路由,服务和资源。单点登录当今广泛使用JWt的一项功能,因为它的开销小,同时又会避免使用session出现作用域的问题

        Jwt组成:JSON Web Token,也就是通过JSON形式作为Web应用中的令牌,用于各方之间安全地将信息作为JSON对象传输,在数据传输过程中还可以完成数据加密,签名等相关处理


提示:以下是本篇文章正文内容,下面案例可供参考

一、使用场景

       用于前后端一个安全地访问,同时可以在传递的Jwt令牌中获得到对应的用户信息

二、使用步骤

        Jwt结构

        1.标头(Header)
        2.有效载荷(Payload)
        3.签名(Signature)
        xxxxxxx.yyyyyyyy.zzzzzz

1.引入库

        <!--   jwt     -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

2.创建Jwt的令牌

代码如下(示例):用于创建Jwt令牌

 Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE,3); //data天
        Map<String, Object> map = new HashMap<>();
        String token = JWT.create()
                //.withHeader(map) //header  不写就用默认HMAC256 也是推荐使用的
                .withClaim("userId", "1111") //payload
                .withClaim("userName", "张三")
                .withExpiresAt(instance.getTime()) //指定令牌过期时间
                .sign(Algorithm.HMAC256("@*%^!@BKF&*W&#$GTIKSDY")); //签名

        System.out.println(token);


 

withClaim: 用于放入Jwt的数据,一般放入个用户名称和唯一标识,密码不用

withExpiresAt: 指定用户这个令牌的过期时间,如果过期了要重新登录的

sign: 用于在生成令牌时额外的数据越复杂越安全

看生成的token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

.eyJ1c2VyTmFtZSI6IuW8oOS4iSIsImV4cCI6MTY3OTAwMDYwNywidXNlcklkIjoiMTExMSJ9

.zYxDCLQumzHaDQutzAECWdYnVPfAF2ueTl_-j0WrwXI

3.解析令牌

        既然生成,我们肯定可以解析,这样才可以验证令牌是否正确

        上代码:

 //验证对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("@*%^!@BKF&*W&#$GTIKSDY")).build();
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6IuW8oOS4iSIsImV4cCI6MTY3ODYxMjM3MywidXNlcklkIjoiYXNkZmFzZGZzYSJ9.MUl7PzhHqF_Z4H3rUJ-hhW7SYjGxqSysAV_40vrbOGY");

        System.out.println(verify);
        System.out.println(verify.getClaim("userId").asString());
        System.out.println(verify.getClaim("userName").asString());
        System.out.println("过期时间:" + verify.getExpiresAt());

注意: 

1. Algorithm.HMAC256("@*%^!@BKF&*W&#$GTIKSDY")  这里要和加密时用的算法一致,同时@*%^!@BKF&*W&#$GTIKSDY 这些也要一致,因为只有这样才可以正确解析
2. .verify("eyJ0eX 这里填入的也就是我们生成的Jwt令牌(token)
3.verify.getClaim("userId").asString() 这里asString()转换为指定类型,一定要和传入的类型一样,不然获得不到值的

整合SpringBoot + Jwt

        jar包 上面有

 1.创建Jwt工具类 

package com.heng.utils;

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;

/**
 * @author 小马
 * @date
 * Jwt工具类
 */
public class JwtUtils {
    
    //额外的数据,越复杂越安全
    private static final String SING_VALUE = "@*%^!@BKF&*W&#$GTIKSDY";
    
    //token的过期时间
    private static final int VALIDITY_DATE = 3; //单位 天
    
    /**
     * 生成token  组成  header.payload.sing
     * payload: 想要在toekn中携带的值 用户标识 名称等
     */
    public static String getToken(Map<String, String> payload) {
        if (SING_VALUE.isEmpty() || SING_VALUE == null) {
            throw new NullPointerException("JWT的签名不能为空");
        }
        if (VALIDITY_DATE == 0) {
            throw new NullPointerException("JWT的过期时间不能为空");
        }
        JWTCreator.Builder builder = JWT.create();
        payload.forEach((k,v) -> {
            builder.withClaim(k, v);
        });
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, VALIDITY_DATE); //data天
        String token = builder
                .withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(SING_VALUE));

        return token;
    }

    /**
     * 验证token合法性
     */
    public static void verify(String token) {
        //验证token
        JWT.require(Algorithm.HMAC256(SING_VALUE)).build().verify(token);
    }

    /**
     * 获得 token 信息
     */
    public static DecodedJWT getTokenInfo(String token) throws Exception {
        return JWT.require(Algorithm.HMAC256(SING_VALUE)).build().verify(token);
    }
}

2.配置拦截器

package com.heng.config.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.heng.utils.JwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;



public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String, Object> map = new HashMap<>();

        //获得请求头中的令牌
        String token = request.getHeader("token");
        try {
            JwtUtils.verify(token); //验证令牌
            return true; //放行
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg", "无效签名");
        } catch (TokenExpiredException e) {
            e.printStackTrace();
            map.put("msg", "token过期!");
        } catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            map.put("msg", "token算法不一致");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("msg", "token无效");
        }
        map.put("state", "无效");
        Object mapJson = JSONObject.toJSON(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().print(mapJson);
        return false;
    }
}

3.让拦截器生效

package com.heng.config.interceptor;

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 InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**")
               //只放行登录验证的接口
                .excludePathPatterns("/user/login");
    }
}

4.编写Controller

@Controller
@RequestMapping(path = "user")
public class UserController {
    

 @PostMapping(path = "login")
    @ResponseBody
    public Result<String> getToken(@RequestParam("userId") String userId,             
                                   @RequestParam("userName") String userName, 
                                   HttpServletResponse response) {
        if (userId == null || "".equals(userId)) {
            return Result.error(500, "id不能为空");
        }
        if (userName == null || "".equals(userName)) {
            return Result.error(500, "姓名不能为空");
        }
        
        //验证用户代码。。。。        
        
        //将token返回给前端,或者放入Http
        Map<String, String> map = new HashMap<>();
        map.put("userId", userId);
        map.put("userName", userName);
        String token = JwtUtils.getToken(map);
        response.setHeader("token", token);
        return Result.success(token);
    }
}

效果图

        

 

 到这里基本就完成了!!!

还有就是请求是在Headers中记得添加token

 可以配置一个统一异常,如果是下面几个错误就是token有问题,重定向到登录页面

常见的异常:

     JWTDecodeException: The string '{"typ":(�|b�[Ȏ��̍M��' doesn't have a valid JSON format.
     1.Jwt解码异常,根据这个token无法解码,token不对
     AlgorithmMismatchException: The provided Algorithm doesn't match the one defined in the JWT's Header.
     2.Jwt的算法不匹配
     TokenExpiredException: The Token has expired on Thu Mar 09 14:58:12 CST 2023.
     3.Jwt令牌过期了
     InvalidClaimException
     4.失效的payload异常,  没有复现出来

总结

        第一次编写博客,后续也会慢慢的更新其他的内容,有问题的可以在下面评论,我会回复的

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值