JWT使用方法

news2025/3/16 13:34:11

目录

基础概念

依赖

生成令牌

工具类

控制层

解析令牌

工具类

网关过滤器

效果


基础概念

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案
为什么使用:

传统的intenet服务的认证是通过session进行的,当用户通过了安全认证后,则在服务端的session对象中保存该用户的认证信息,这样该用户对服务的访问被认为是安全的。这种模式的最大问题是没有分布式架构,不方便进行横向扩展,这种模式只适合于单体应用模式。如果需要进行服务集群则需要处理好共享session的问题。 如果一个庞大的系统需要按服务分解为多个独立的服务,使用分布式架构,则这种方式更难处理。使用jwt可以方便的处理上面提到的问题。
验证过程:

客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中,此后在于服务器的交互中都携带者JWT信息,它验证的方法其实很简单,只要把header做base64url解码,就能知道JWT用的什么算法做的签名,然后用这个算法,再次用同样的逻辑对header和payload做一次签名,并比较这个签名是否与JWT本身包含的第三个部分的串是否完全相同,只要不同,就可以认为这个JWT是一个被篡改过的串。

依赖

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!--javax.xml.bind.DatatypeConverter java8 以后要加-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

生成令牌

在登录过程中新建令牌,所以需要写在生产者中,并且根据数据库的用户和密码登录并判断其权限,根据给定的母版key、用户名、密码、权限生成其令牌。注意,这里设定了1小时候令牌过期。

工具类

@Component
public class JwtUtil {
    //加密 解密时的密钥 用来生成key
    public static final String JWT_KEY = "IT1995";

    /**
     * \* 生成加密后的秘钥 secretKey
     * <p>
     * \* @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length,
                "AES");
        return key;
    }

    /**
     * \* 登录成功后生成token* \* @param id
     * \* @param account
     * \* @param role
     * \* @param ttlMillis
     * \* @return
     */
    public static String createJWT(String id, Account account, String role, long
            ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
        long nowMillis = System.currentTimeMillis();//生成JWT的时间
        Date now = new Date(nowMillis);
        SecretKey key = generalKey();//生成签名的时候使用的秘钥secret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
        Map claims = new HashMap();
        claims.put("name", account.getUsername());
        claims.put("role", role);
        JwtBuilder builder = Jwts.builder()//这里其实就是new一个JwtBuilder,设置jwt的body
                .setClaims(claims) //如果有私有声明,一定要先设置这个自己创 建的私有的声明,这 个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声 明的 创建用户表
                .setId(id) //设置jti(JWT ID):是JWT的唯一标识,根 据业务需要,这个可以设置为 一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
                .setIssuedAt(now) //iat: jwt的签发时间
// .setSubject(subject) //sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。
                .signWith(signatureAlgorithm, key);//设置签名使用的签名算法和签名使用的秘钥
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp); //设置过期时间
        }
        return builder.compact(); //就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx这样的jwt
    }
   
    /**
     * \* 密码解密对比方法4.编写mapper
     * 5.编写service根据用户名取的用户信息和权限
     * \* @param password
     * \* @param repassword
     * \* @return
     */
    public static boolean matchsPassword(String password, String repassword) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder.matches(password, repassword);
    }
}

控制层

@RestController
public class LoginController {
    @Autowired
    AccountService accountService;

    @RequestMapping("/login")
    public String Login(Account account) {
        String token = "没有token";
        //通过用户名拿到用户实体类
        Account result = accountService.loginByUserName(account.getUsername());
        if (result != null) {
            //然后进行密码的加密后的比较
            boolean b = JwtUtil.matchsPassword(account.getPassword(), result.getPassword());
            //如果密码一致表示登录成功
            if (result != null && b) {
                List<Authority> author = accountService.findAuthoritiesByUsername(account.getUsername());
                token = JwtUtil.createJWT(UUID.randomUUID().toString(), result, author.get(0).getAuthority(), 3600L * 1000);
            }
        }
        return token;
    }
}

解析令牌

给定令牌并解析,根据不同token,解析出对应的用户名、密码和权限,并判断访问内容,根据访问路径中的敏感词判断是否有权限查看页面。

工具类

@Component
public class JwtUtil {
    //加密 解密时的密钥 用来生成key
    public static final String JWT_KEY = "IT1995";

    /**
     * \* 生成加密后的秘钥 secretKey
     * <p>
     * \* @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length,
                "AES");
        return key;
    }

    /**
     * \* 解析token
     * \* @param jwt
     * \* @return
     */
    public static Claims parseJWT(String jwt) {
        SecretKey key = generalKey(); //签名秘钥,和生成的签名的秘钥一模一样
        Claims claims = Jwts.parser() //得到DefaultJwtParser
                .setSigningKey(key) //设置签名的秘钥
                .parseClaimsJws(jwt).getBody();//设置需要解析的jwt
        return claims;
    }
}

网关过滤器

@Component
public class gatewayConfig implements GlobalFilter, Ordered {
    private static final String AUTHORIZE_TOKEN = "token";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestPath = exchange.getRequest().getPath().value();
        // 1. 获取请求
        ServerHttpRequest request = exchange.getRequest();
        //2. 则获取响应
        ServerHttpResponse response = exchange.getResponse();
        //3. 如果是登录请求则放行
        if (request.getURI().getPath().contains("/login") || request.getURI().getPath().contains("/logout")) {
            return chain.filter(exchange);
        }
        //4. 获取请求头
        HttpHeaders headers = request.getHeaders();
        //5. 请求头中获取令牌
        String token = headers.getFirst(AUTHORIZE_TOKEN);
        //6. 判断请求头中是否有令牌
        if (StringUtils.isEmpty(token)) {
            //7. 响应中放入返回的状态吗, 没有权限访问
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //8. 返回
            return response.setComplete();
        }
        //9. 如果请求头中有令牌则解析令牌
        try {
            Claims claims = JwtUtil.parseJWT(token);
            //获取token中的权限然后根据权限做访问权限
            String role = (String) claims.get("role");
            System.out.println(role);
            if (role.equals("vip")) {
                return chain.filter(exchange);
            }
            if (role.equals("common")) {
                if (request.getURI().getPath().contains("/vip")) {
                    response.setStatusCode(HttpStatus.FORBIDDEN);
                    //11. 返回
                    return response.setComplete();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            //10. 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现
            response.setStatusCode(HttpStatus.FORBIDDEN);
            //11. 返回
            return response.setComplete();
        }
        //12. 放行
        return chain.filter(exchange);
    }


    @Override
    public int getOrder() {
        return 0;
    }
}

效果

只有vip用户才能查看vip页面,普通用户查看vip页面403权限不足错误。如果没有登录令牌查看页面,401错误。

没有登录令牌

vip登录成功

普通用户访问vip 403

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

局域网桌面监控软件哪个好用?良心推荐

如何有效地监控和管理内部员工的计算机使用行为&#xff0c;防范潜在的安全风险&#xff0c;提高工作效率&#xff0c;是众多企业管理者关注的焦点。 而一款优秀的局域网桌面监控软件无疑能为企业的IT治理提供有力支撑。 小编在此给大家推荐一款好用的局域网桌面监控软件——域…

stm32H743不要将主频设置到480MHz

0 问题描述 本文使用的stm32H743是V版本&#xff0c;支持最高480MHz的主频。但在将主频设置为480MHz之后&#xff0c;使用FDCAN的回环模式出现了各种接收不到的异常问题。经过一番排查&#xff0c;将主频修改到400MHz&#xff0c;同时降低芯片内部LDO输出电压后恢复了正常。 …

深入理解NumPy与Pandas【numpy模块及Pandas模型使用】

二、numpy模块及Pandas模型使用 numpy模块 1.ndarray的创建 import numpy as np anp.array([1,2,3,4]) bnp.array([[1,2,3,4],[5,6,7,8]]) print(a) #[1 2 3 4] print(b) #[[1 2 3 4][5 6 7 8]] 1.1使用array()函数创建 numpy.array(object, dtype None, copy True, ord…

域内攻击 ----->约束非约束委派攻击

在域中&#xff0c;除了我们常见的横向移动以外&#xff0c;还有很多攻击&#xff0c;像什么kerberoasting&#xff0c;委派攻击&#xff0c;NTLMrelay啊...... 还有很多&#xff08;暂时只知道这些&#xff09; 以前在一篇公众号看到的一个笑话也荟萃了网安的一些攻击手法&am…

设计模式在芯片验证中的应用——单例

一、单例模式 单例模式(Singleton)是一种创建型设计模式&#xff0c;能够保证一个类只有一个实例&#xff0c; 并提供一个访问该实例的全局节点。验证环境配置(configuration)类、超时(timeout)处理类等可以使用单例实现。比如说验证环境需要在特定场景中监测特定接口上的超时事…

【机器学习300问】97、机器学习中哪些是凸优化问题,哪些是非凸优化问题?

在机器学习的领域中&#xff0c;多数模型的参数估计问题实质上可以转化为优化问题。鉴于机器学习模型的多样性&#xff0c;不同的模型会对应着不同的损失函数&#xff0c;进而形成各具特色的优化问题。了解优化问题的形式和特点&#xff0c;对于提升我们求解模型参数的效率和准…

在 Visual Studio 2022 (VS2022) 中删除 Git 分支的步骤如下

git branch -r PS \MauiApp1> git push origin --delete “20240523备份” git push origin --delete “20240523备份”

推荐五个线上兼职,在家也能轻松日入百元,适合上班族和全职宝妈

在这个瞬息万变的时代&#xff0c;你是否也曾考虑过在繁忙的工作之外&#xff0c;寻找一份兼职副业来补贴家用&#xff0c;同时保持生活的多样性&#xff1f;别急&#xff0c;现在就让我为你揭秘五个可靠的日结线上兼职岗位&#xff0c;助你轻松迈向财务自由之路&#xff01; 一…

地质考察AR远程交互展示系统辅助老师日常授课

广东这片充满活力的土地&#xff0c;孕育了一家引领ARVR科技潮流的杰出企业——深圳华锐视点&#xff0c;作为一家专注于VR/AR技术研究与业务开发的先锋公司。多年来&#xff0c;我们不断突破技术壁垒&#xff0c;将AR增强现实技术与各行各业的实际需求完美结合&#xff0c;助力…

基于分块贝叶斯非局部均值优化(OBNLM)的图像去噪算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 块定义与相似度计算 ​4.2 贝叶斯框架下的加权融合 4.3 加权最小均方误差估计 5.完整程序 1.程序功能描述 基于分块贝叶斯非局部均值优化(OBNLM)的图像去噪算法matlab仿真&#xff0c…

JAVA线程池的线程数量配置

一 JAVA线程池的线程数量配置 关于线程的配置&#xff0c;线程数量配置多少这个问题呢&#xff1f;往往不同的环境与不同的线程中的代码决定其配置的线程的数量。 二 常见的线程量配置 最常见的方式根据线程中处理的代码划分为CPU密集型或IO密集型&#xff1a; CPU密集型&…

react实现table可拖拽表头(给react-jss样式传递参数、滚动条样式)

目录 react实现table可拖拽表头安装依赖resizableTitle / index.tsxdrapTable.tsx使用DragTable 组件滚动条样式效果 react实现table可拖拽表头 安装依赖 yarn add react-resizable yarn add react-jssresizableTitle / index.tsx import { createUseStyles } from react-js…

【电子学会】2023年09月图形化一级 -- 保护环境

保护环境 1. 准备工作 &#xff08;1&#xff09;删除角色小猫&#xff0c;添加角色Wizard&#xff0c;Bear-walking&#xff1b; &#xff08;2&#xff09;添加背景Desert和Forest。 2. 功能实现 &#xff08;1&#xff09;调整魔法师和熊的大小为50&#xff1b; &…

Linux文本处理三剑客(详解)

一、文本三剑客是什么&#xff1f; 1. 对于接触过Linux操作系统的人来说&#xff0c;应该都听过说Linux中的文本三剑客吧&#xff0c;即awk、grep、sed&#xff0c;也是必须要掌握的Linux命令之一&#xff0c;三者都是用来处理文本的&#xff0c;但侧重点各不相同&#xff0c;a…

MySQL---通用语法及分类

目录 一、SQL通用语法 二、 SQL分类 1.DDL 1.1 DDL数据库操作 1.2 DDL表操作---查询 1.3 DDL表操作---创建​编辑 1.4 DDL表操作---数据类型 1.5 DDL表操作---修改 1.6 DDL表操作---删除 1.7 DDL总结 2. 图形化界面工具DataGrip 2.1 创建 2.2 使用 3. DML 3.1 DML介绍 3.2 DM…

基于开源ATmega8 无感BLDC程序移植到ATmega328PB

基于开源ATmega8 无感BLDC程序移植到ATmega328PB &#x1f516;基于Atmel Studio 7.0开发环境。&#x1f955;开源原项目资源地址&#xff1a;https://svn.mikrokopter.de/websvn/listing.php?repnameBL-Ctrl&path%2F&&#x1f4cd;原理图和PCB资源 BL-Ctrl v2.0 in E…

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

文章目录 前言一、VGA概述1.1 简述1.2 管脚定义1.3 VGA显示原理1.4 VGA时序标准1.5 VGA 显示模式及相关参数 二、VGA显示自定义的汉字字符2.1 点阵汉字生成2.2 生成BMP文件2.3 生成txt文件2.4 实现效果 三、VGA显示条纹3.1 实现流程3.2 实现效果 四、VGA输出一幅彩色图像4.1 bm…

从旅游广告联想到《桃花源记》

近日收到《长江头条网》等知名网络自媒体相邀,促我写点儿旅游题材的文案。虽说笔者游历过许多名山大川的绝美风景区,但那是在70岁之前的事儿了。如今年逾78岁,纵使有少许自有资本能够支持出游,可体力难撑,岂不是花钱买罪受吗?而且,写没有亲身经历过的事挺难,即便发表出…

Plotly库利用滑块创建数据可视化

使用了Plotly库来创建一个数据可视化图表&#xff0c;并使用滑块来控制显示哪些数据 import plotly.graph_objects as go from plotly.subplots import make_subplots# 示例数据 x [1, 2, 3, 4, 5] y1 [1, 2, 3, 4, 5] y2 [5, 4, 3, 2, 1] y3 [2, 3, 1, 5, 4]# 创建子图 f…

基于jeecgboot-vue3的Flowable增加流程支持组件与element-plus组件导入支持

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、package.json文件需要增加相关流程组件&#xff0c;如下 "dependencies": {"element-plus/icons-vue": "^2.3.1","highlightjs/vue-plugin":…