SpringBoot集成JWT token实现权限验证

JWT=JSON Web Token

1. JWT的组成

JWT==Header,Payload,Signature==>abc.def.xyz

地址:JSON Web Tokens - jwt.er

1.1 Header

Header:标头。

两个组成部分:令牌的类型(JWT)和所使用的签名算法,经过Base64 Url编码后形成的JWT的第一部分。

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

1.2 Payload

Payload---有效负载。存放用户自定义消息

注意点:是以明文的形式进行展示,以Base64进行编码。

{
    “sub":"123",
    "name":"jon",
    "admin":true
}

1.3 Signature

signature--签名。使用标头的算法和私钥对第一部分和第二部分进行加密,通过Base64 Url编码后形成JWT的第三部分。

var encodeString =base64UrlEncode(header)+"."+base64UrlEncode(payload);
var signature=HMACSHA356(encodeString,secret);

2.JWT的基本使用

1.导入pom JWT依

JDK1.8以下的加入JWT依赖即可

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

JDK1.8以上的加上其他

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>

2.创建JWT

    //毫秒
    private long time=1000*60*60*24;
    //签名
    private String signature="admin";

    /*JWT加密*/
    @Test
    public void jwt(){
        //构建JWT对象:Jwts.builder()
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken = jwtBuilder
                //header:头部
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload:载荷
                .claim("username", "tom")
                .claim("role", "admin")
                .setSubject("admin-test")
                //有效时间===>一天=当前时间+24小时
                //获得当前的系统时间:System.currentTimeMillis()
                .setExpiration(new Date(System.currentTimeMillis() + time))
                //设置id字段
                .setId(UUID.randomUUID().toString())
                //signature:签名
                //注意点:这个签名算法要与前面的算法一致
                //设置加密算法和签名
                .signWith(SignatureAlgorithm.HS256, signature)
                //将前面3个重要信息拼接起来,使用”."来连接
                .compact();
        System.out.println(jwtToken);
    }

3.验证JWT

    @Test
    /*验证JWT*/
    public void checkJwt(){
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM2MzgzMDMsImp0aSI6ImU5ZjY3ZjBhLWE0NTAtNGYzYy1hYTY3LTU3ZGMwOWRjMDM4ZCJ9.FxA5c91E2bk2KW1rdMo8jlmClXgn7r2mVSaXs19Qzzk";
        //Jwts.parser():解析
        JwtParser jwtParser = Jwts.parser();
        //验证该token是否符合JWT规则
        boolean result = Jwts.parser().isSigned(token);
        System.out.println(result);//true
    }

4.解析JWT

    @Test
    /*解析JWT*/
    public void parseJwt(){
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM2MzgzMDMsImp0aSI6ImU5ZjY3ZjBhLWE0NTAtNGYzYy1hYTY3LTU3ZGMwOWRjMDM4ZCJ9.FxA5c91E2bk2KW1rdMo8jlmClXgn7r2mVSaXs19Qzzk";
        //获取JWT的解析对象
        JwtParser jwtParser = Jwts.parser();
        //通过signature对token进行签名,解开
        //parseClaimsJws:将JWT转换为key-value的形式,通过key来获取对应的value
        //Jws<Claims>:类似于Map集合
        Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
        //获取Jws对象中的数据:get(key)表示根据key来获取value
        //相当于将header和payload封装为一个claims
        Claims claims = claimsJws.getBody();//存储的是用户保存的数据
        Object username = claims.get("username");
        System.out.println(username);
        Object role = claims.get("role");
        System.out.println(role);
        String id = claims.getId();
        System.out.println(id);
        //签名
        String subject = claims.getSubject();
        System.out.println(subject);
        //有效期
        Date time = claims.getExpiration();
        System.out.println(time);
    }

3.SpringBoot + vue +JWT

 1.导入pom JWT依

JDK1.8以下的加入JWT依赖即可

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

JDK1.8以上的还要加上以下依赖

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>

2.导入工具类

public class JwtUtil {

    //毫秒
    private static long time=1000*60*60*24;
    //签名
    private static String signature="admin";

    public static String createToken(){
        //构建JWT对象:Jwts.builder()
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken=jwtBuilder
                //header
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload
                .claim("username", "admin")
                .claim("role", "admin")
                .setSubject("admin-test")
                //有效时间===>一天=当前时间+24小时
                //获得当前的系统时间:System.currentTimeMillis()
                .setExpiration(new Date(System.currentTimeMillis()+time))
                .setId(UUID.randomUUID().toString())
                //signature
                //注意点:这个签名算法要与前面的算法一致
                .signWith(SignatureAlgorithm.HS256,signature)
                //将前面3个重要信息拼接起来
                .compact();
        return jwtToken;
    }
}

3.在后台解决跨域问题

@Configuration//配置类
public class CoreConfiguration implements WebMvcConfigurer {


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//所有接口
                .allowCredentials(true)//是否发送Cookie
                .allowedOriginPatterns("*")//支持域
                .allowedMethods("GET","POST","PUT","DELETE")//支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

4.前台登录界面

5.前端代码

  methods:{
    handleSubmit(){
      this.$refs.ruleForm.validate((valid)=>{
        if(valid){
          let _this=this
          axios.get("http://localhost:8080/login",
              {param:_this.ruleForm}).then(function (response){
            console.log(response.data)
          })
        }
      })
    }
  }

6.进行路由跳转,并且将用户信息存到本地存储中

JSON.stringify-->将JSON转换为字符串

    handleSubmit(){
      this.$refs.ruleForm.validate((valid)=>{
        if(valid){
          let _this=this
          axios.get("http://localhost:8080/login",
              {param:_this.ruleForm})./*带着用户输入的用户名和密码*/
              then(function (response){
                console.log(response.data)
                //如果data不为空,则表示登录成功
                if(response.data!=null){
                  //使用localStorage
                  //将JSON转换为字符串
                  localStorage.setItem('access-admin',JSON.stringify(response.data))
                  //跳转到首页
                  _this.$router.replace({path:"/"})
                  }
                })
          }
      })
    }

7.将用户信息展示到页面中

JSON.parse--->将字符串转换为JSON

<template>
<div>
  欢迎回来:{{admin.username}}
</div>
</template>

  data(){
    return{
      admin:''
    }
  },
  created() {
//获取数据
    this.admin=JSON.parse(window.localStorage.getItem("access-admin"));
  },

8.添加验证用户信息是否存在【在路由中写】

/router/index.js

router.beforeEach((to,from,next)=>{
    if(to.path.startsWith('/login')){
        window.localStorage.removeItem('access-admin')
        next()
    }else {
        let admin=JSON.parse(window.localStorage.getItem('access-admin'))
        if(!admin){
            next({path:'/login'})
        }else {
            //校验token合法性
            axios({
                url:'http://localhost:8080/checkeToken',
                method:'get',
                headers:{
                    token:admin.token
                }
            }).then((response)=>{
                if(!response.data){
                    console.log("校验失败");
                    next({path:'/error'})
                }
            })
        }
    }
})

9.后端验证Token方法

UserController

    /**
     * 验证token方法
     */
    @GetMapping("/checkToken")
    public Boolean checkToken(HttpServletRequest request){
        //因为前端是将数据存储在header,所以我们要是有getHeader
        String token = request.getHeader("token");
        return JwtUtil.checkToken(token);
    }

JwtUtil

    /**
     * 校验token是否正确
     */
    public static boolean checkToken(String token){
        if (token==null){
            return false;
        }
        try {
            //解析
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

4.Springboot+JWT

User

@Data
public class User {
    private String username;
    private String password;
    private String token;
}

UserController:生成JWT令牌

public class UserController {

    private final String USERNAME = "admin";
    private final String PASSWORD = "123123";

    @GetMapping("/login")
    public User login(User user){
        //判断是否正确
        if(USERNAME.equals(user.getUsername()) && PASSWORD.equals(user.getPassword())){
            //添加token;token保存到user对象
            //定义一个工具类,将生成JWT
            user.setToken(JwtUtil.createToken());
            return user;
        }
        return null;
    }
}

JwtUtil:生成JWT令牌

public class JwtUtil {

    //毫秒
    private static long time=1000*60*60*24;
    //签名
    private static String signature="admin";

    public static String createToken(){
        //构建JWT对象:Jwts.builder()
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken=jwtBuilder
                //header
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload
                .claim("username", "admin")
                .claim("role", "admin")
                .setSubject("admin-test")
                //有效时间===>一天=当前时间+24小时
                //获得当前的系统时间:System.currentTimeMillis()
                .setExpiration(new Date(System.currentTimeMillis()+time))
                .setId(UUID.randomUUID().toString())
                //signature
                //注意点:这个签名算法要与前面的算法一致
                .signWith(SignatureAlgorithm.HS256,signature)
                //将前面3个重要信息拼接起来
                .compact();
        return jwtToken;
    }
}

【前端直接传递token】

JwtUtil:验证JWT是否过期

    /**
     * 校验token是否过期
     */
    public static boolean checkToken(String token){
        if (token==null || token==""){
            return false;//false表示令牌过期
        }
        try {
            //拿到JWT对象
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

UserController:验证JWT是否过期

    /**
     * 验证token是否过期:前端传递token
     */
    @GetMapping("/checkToken")
    public Boolean checkToken(String token){
        return JwtUtil.checkToken(token);
    }

【将Token放入请求头中,使用request】

 JwtUtil:验证JWT是否过期

    /**
     * 校验token是否过期
     */
    public static boolean checkToken(String token){
        if (token==null || token==""){
            return false;//false表示令牌过期
        }
        try {
            //拿到JWT对象
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

UserController:验证JWT是否过期

    /**
     * 验证token是否过期:前端将数据封装在请求头中
     * @param request
     * @return
     */
    public boolean checkToken(HttpServletRequest request){
        //getHeader中的key要与前端通过一致
        String token = request.getHeader("token");//key-->token
        return JwtUtil.checkToken(token);
    }

解决跨域问题

参考:SpringBoot跨域请求的问题_m0_63077733的博客-CSDN博客

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 所有接口
                .allowCredentials(true) // 是否发送 Cookie
                .allowedOriginPatterns("*") // 支持域
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

拦截器实现Token验证

@Configuration
public class TokenInterceptor implements HandlerInterceptor {

    //在请求处理方法被调用之前被调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //前提:token放在请求头中
        String token = request.getHeader("token");
        if (!JwtUtil.checkToken(token)) {
            return false;//验证失败
        }
        return true;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/100089.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一、Mycat2介绍与下载安装

第一章 入门概述 1.1 是什么 Mycat 是数据库中间件。 1、数据库中间件 中间件&#xff1a;是一类连接软件组件和应用的计算机软件&#xff0c;以便于软件各部件之间的沟 通。 例子&#xff1a;Tomcat&#xff0c;web中间件。 数据库中间件&#xff1a;连接java应用程序和数据库…

CSS3D+动画

CSS3D 1.css3D 给父元素设置 perspective:景深:近大远小的效果900-1200px这个范围内 transform-style:是否设置3D环境 flat 2D环境 默认值 perserve-3D环境 3D功能函数 1.位移: translateZ()translate3D(x,y,z) <!DOCTYPE html> <html lang"en"><h…

Elasticsearch:自动使用服务器时间设置日期字段并更新时区

在大多数情况下&#xff0c;你的数据包含一个以 create_date 命名的字段。 即使没有日期字段&#xff0c;处理各种格式和时区的日期对数据仓库来说也是一个重大挑战。 与此类似&#xff0c;如果要检测变化的数据&#xff0c;则必须准确设置日期字段。 在 Elasticsearch 中还有…

windows vmware17虚拟机导出、导入

我采用的是vmware17版本的虚拟机软件 直接拷贝VM虚拟机文件 导出 查看虚拟机所在路径 复制整个文件夹&#xff0c;可以先压缩介绍文件大小&#xff0c;拷贝到需要还原该虚拟机的电脑上 导入 在目的电脑上需要安装vnware17版本的虚拟机软件 直接打开vmware17&#xff0c; 选…

一、项目介绍 二、什么是内存池?

目录 一、项目介绍这个项目是做什么的&#xff1f; 二、什么是内存池&#xff1f;2.1 什么是池化技术&#xff1f;2.2 内存池2.3 内存池主要解决什么问题&#xff1f;2.4 malloc 一、项目介绍 这个项目是做什么的&#xff1f; 当前项目是实现一个高并发的内存池&#xff0c;它…

官方推荐使用的OkHttp4网络请求库全面解析(Android篇)

作者&#xff1a;cofbro 前言 现在谈起网络请求&#xff0c;大家肯定下意识想到的就是 okhttp 或者 retrofit 这样的三方请求库。诚然&#xff0c;现在有越来越多的三方库帮助着我们快速开发&#xff0c;但是对于现在的程序员来说&#xff0c;我们不仅要学会如何去用&#xff…

视频监控/视频汇聚/视频云存储EasyCVR平台HLS流集成在小程序无法播放的问题排查

安防视频/视频云存储/视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求&#xff0c;让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上&#xff0c;视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频…

Java 枚举是什么?什么是枚举类?枚举类的用途?

目录 1. 什么是枚举&#xff1f; 2. 枚举类 3. 枚举类的用途 1. 什么是枚举&#xff1f; 我们可以从字面意思来理解&#xff0c;枚&#xff1a;一枚一枚的&#xff0c;举&#xff1a;举例&#xff0c;举出&#xff0c;将二者意思结合起来可以理解为一个一个的举出。 这样听…

21.3 CSS 背景属性

1. 背景颜色 background-color属性: 设置元素的背景颜色. 它可以接受各种颜色值, 包括命名颜色, 十六进制颜色码, RGB值, HSL值等.快捷键: bctab background-color:#fff;<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"…

Revit SDK:AutoJoin 自动合并体量

前言 Revit 有一套完整的几何造型能力&#xff0c;每一个体量都是一个GenericForm&#xff0c;这些体量可以通过拉伸、扫掠等创建。这个例子介绍如何将他们合并成一个体量。 内容 合并体量的关键接口&#xff1a; // Autodesk.Revit.DB.Document public GeomCombination Com…

【ArcGIS Pro二次开发】(65):进出平衡SHP转TXT、TXT转SHP

最近一个小伙伴提了这么一个需求&#xff0c;需要把TXT和SHP进行互转。 这种TXT文件其实遇到了好几个版本&#xff0c;都有一点小差异。之前已经做过一个TXT转SHP的工具&#xff0c;但好像不适用。于是针对这个版本&#xff0c;做了互转的2个工具。 【SHP转TXT】 一、要实现的…

Go几种读取配置文件的方式

比较有名的方案有 使用viper管理配置[1] 支持多种配置文件格式&#xff0c;包括 JSON,TOML,YAML,HECL,envfile&#xff0c;甚至还包括Java properties 支持为配置项设置默认值 可以通过命令行参数覆盖指定的配置项 支持参数别名 viper[2]按照这个优先级&#xff08;从高到低&am…

爬虫逆向实战(二十八)--某税网第一步登录

一、数据接口分析 主页地址&#xff1a;某税网 1、抓包 通过抓包可以发现登录接口是factorAccountLogin 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看载荷模块可以发现有一个datagram 和 一个signature加密参数 请求头是否加密&#xff1f; 通过查看“标…

11 mysql float/double/decimal 的数据存储

前言 这里主要是 由于之前的一个 datetime 存储的时间 导致的问题的衍生出来的探究 探究的主要内容为 int 类类型的存储, 浮点类类型的存储, char 类类型的存储, blob 类类型的存储, enum/json/set/bit 类类型的存储 本文主要 的相关内容是 float, decimal 类类型的相关数据…

电脑提示找不到concrt140.dll怎么修复?concrt140.dll快速修复方法

今天&#xff0c;我将和大家分享一个关于电脑计算机中丢失concrt140.dll文件的问题及其修复方法。希望通过这次演讲&#xff0c;能够帮助大家解决在日常使用电脑过程中遇到的问题&#xff0c;提高我们的工作效率。 首先&#xff0c;让我们来了解一下concrt140.dll是什么。concr…

爬虫--爬取自己想去的目的的车票信息

前言&#xff1a; 本篇文章主要作为一个爬虫项目的小练习&#xff0c;来给大家进行一下爬虫的大致分析过程以及来帮助大家在以后的爬虫编写中有一个更加清晰的认识。 一&#xff1a;环境配置 Python版本&#xff1a;3.7 IDE:PyCharm 所需库&#xff1a;requests&#xff0…

ShardingJDBC——基于JPA的读写分离实战

摘要 本博文主要介绍基于JPA的读写分离实战&#xff0c;帮助大家更好的学会使用读写分离。透明化读写分离所带来的影响&#xff0c;让使用方尽量像使用一个数据库一样使用主从数据库集群&#xff0c;是ShardingSphere读写分离模块的主要设计目标。 一、读写分离库的场景和设计…

CSRF与XSS结合利用

文章目录 修改cms网站后台管理员密码成功登录总结 修改cms网站后台管理员密码 CSRF和XSS结合的JS代码&#xff1a; <script> xmlhttp new XMLHttpRequest(); xmlhttp.open("post","http://10.4.7.130/cms/admin/user.action.php",false); xmlhttp…

【位运算】leetcode面试题:消失的两个数字

一.题目描述 消失的两个数字 二.思路分析 本题难度标签是困难&#xff0c;但实际上有了只出现一次的数字iii这道题的铺垫&#xff0c;本题的思路还是很容易想到的。 温馨提示&#xff1a;阅读本文前可以先查看我的【位运算】专栏的第一篇文章&#xff0c;其中包含位运算这类…

NFTScan | 08.21~08.27 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。周期&#xff1a;2023.08.21~ 2023.08.27 NFT Hot News 01/ NFT 品牌体验平台 Recur 将于 11 月 16 日彻底关闭&#xff0c;此前曾获 5000 万美元融资 8 月 21 日&#xff0c;NFT 品牌体验平台 Recur 在 X…