后台管理系统的通用权限解决方案(九)SpringBoot整合jjwt实现登录认证鉴权

  • 1)创建maven工程jjwt-login-demo,并配置其pom.xml文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version><relativePath/></parent><groupId>org.example</groupId><artifactId>jjwt-login-demo</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.1.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
</project>
  • 2)创建resources/keys目录,将通过RSA算法生成的公钥和私钥复制到此目录下

  • 3)在resources目录下创建application.yml文件,配置jjwt相关配置
# jjwt相关配置
auth:token:expire: 3600 #令牌失效时间,单位秒priKey: keys/pri.key #私钥地址pubKey: keys/pub.key #公钥地址
  • 4)创建属性类AuthTokenProperties,用于接收application.yml文件中的配置
package com.itweid.jjwt.config;import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;@Data
@NoArgsConstructor
@ConfigurationProperties(prefix = "auth.token")
public class AuthTokenProperties {/*** 过期时间。默认2小时=7200秒*/private Integer expire = 7200;/*** 私钥*/private String priKey;/*** 公钥*/private String pubKey;
}
  • 5)定义实体类LoginUserTokenLoginUser对象保存当前登录用户的信息,这些信息被加密后则使用Token对象保存
package com.itweid.jjwt.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements Serializable {/*** id*/private Long userId;/*** 账号*/private String account;/*** 姓名*/private String name;/*** 手机*/private String telephone;
}
package com.itweid.jjwt.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Token implements Serializable {private static final long serialVersionUID = -8482946147572784305L;/*** token*/private String token;/*** 有效时间:单位:秒*/private Integer expire;
}
  • 6)定义一个异常类BaseException,用于接收token生成和解析时的异常
package com.itweid.jjwt.exception;import lombok.Getter;@Getter
public class BaseException extends RuntimeException {protected int code;protected String message;public BaseException(int code, String message) {this.code = code;this.message = message;}
}
  • 7)定义RSA帮助类RsaKeyHelper,封装获取公钥和密钥的方法
package com.itweid.jjwt.utils;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;/*** RSA帮助类*/
public class RsaKeyHelper {/*** 获取公钥* @param filename 公钥文件地址* @return PublicKey* @throws IOException* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public PublicKey getPublicKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(filename);try (DataInputStream dis = new DataInputStream(resourceAsStream)) {byte[] keyBytes = new byte[resourceAsStream.available()];dis.readFully(keyBytes);X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePublic(spec);}}/*** 获取密钥* @param filename 密钥文件地址* @return PrivateKey* @throws IOException* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public PrivateKey getPrivateKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(filename);try (DataInputStream dis = new DataInputStream(resourceAsStream)) {byte[] keyBytes = new byte[resourceAsStream.available()];dis.readFully(keyBytes);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePrivate(spec);}}
}
  • 8)定义JWT帮助类JwtHelper,封装生成token、从token中获取登录用户信息的方法
package com.itweid.jjwt.utils;import com.itweid.jjwt.exception.BaseException;
import com.itweid.jjwt.pojo.LoginUser;
import com.itweid.jjwt.pojo.Token;
import io.jsonwebtoken.*;import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;public class JwtHelper {private static final RsaKeyHelper RSA_KEY_HELPER = new RsaKeyHelper();private static final String JWT_KEY_ACCOUNT = "account";private static final String JWT_KEY_NAME = "name";private static final String JWT_KEY_TELEPHONE = "telephone";/*** 生成token* @param loginUser* @param priKeyPath* @param expire* @return* @throws BaseException*/public static Token generateToken(LoginUser loginUser, String priKeyPath, int expire) throws BaseException {JwtBuilder jwtBuilder = Jwts.builder()//设置主题.setSubject(String.valueOf(loginUser.getUserId())).claim(JWT_KEY_ACCOUNT, loginUser.getAccount()).claim(JWT_KEY_NAME, loginUser.getName()).claim(JWT_KEY_TELEPHONE, loginUser.getTelephone());return generateToken(jwtBuilder, priKeyPath, expire);}/*** 生成token* @param builder* @param priKeyPath* @param expire* @return Token* @throws BaseException*/protected static Token generateToken(JwtBuilder builder, String priKeyPath, int expire) throws BaseException {try {// 获取过期时间ZonedDateTime zdt = LocalDateTime.now().plusSeconds(expire).atZone(ZoneId.systemDefault());// 返回的字符串便是我们的jwt串了String compactJws = builder.setExpiration(Date.from(zdt.toInstant()))//设置算法(必须).signWith(SignatureAlgorithm.RS256, RSA_KEY_HELPER.getPrivateKey(priKeyPath)).compact();return new Token(compactJws, expire);} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {throw new BaseException(1, "生成token失败");}}/*** 获取token中的用户信息* @param token* @param pubKeyPath* @return LoginUser* @throws BaseException*/public static LoginUser getLoginUserFromToken(String token, String pubKeyPath) throws BaseException {Jws<Claims> claimsJws = parserToken(token, pubKeyPath);Claims body = claimsJws.getBody();String userId = body.getSubject();String account = (String) body.get(JWT_KEY_ACCOUNT);String name = (String) body.get(JWT_KEY_NAME);String telephone = (String) body.get(JWT_KEY_TELEPHONE);return new LoginUser(Long.parseLong(userId), account, name, telephone);}/*** 使用公钥解析token* @param token* @param pubKeyPath 公钥路径* @return Jws<Claims>* @throws BaseException*/private static Jws<Claims> parserToken(String token, String pubKeyPath) throws BaseException {try {return Jwts.parser().setSigningKey(RSA_KEY_HELPER.getPublicKey(pubKeyPath)).parseClaimsJws(token);} catch (ExpiredJwtException ex) {//过期throw new BaseException(2, "token已过期");} catch (SignatureException ex) {//签名错误throw new BaseException(3, "签名错误");} catch (IllegalArgumentException ex) {//token为空throw new BaseException(4, "token为空");} catch (Exception e) {// 其他错误throw new BaseException(5, "未知错误," + e.getMessage());}}
}
  • 9)定义token工具类TokenUtils,读取application.yml配置文件中的配置生成token或解析token
package com.itweid.jjwt.utils;import com.itweid.jjwt.config.AuthTokenProperties;
import com.itweid.jjwt.exception.BaseException;
import com.itweid.jjwt.pojo.LoginUser;
import com.itweid.jjwt.pojo.Token;
import lombok.AllArgsConstructor;/*** token工具类*/
@AllArgsConstructor
public class TokenUtils {private AuthTokenProperties authTokenProperties;/*** 生成token* @param loginUser* @param expire* @return Token* @throws BaseException*/public Token generateLoginUserToken(LoginUser loginUser, Integer expire) throws BaseException {if (expire == null || expire <= 0) {expire = authTokenProperties.getExpire();}return JwtHelper.generateToken(loginUser, authTokenProperties.getPriKey(), expire);}/*** 解析token* @param token* @return* @throws BaseException*/public LoginUser getLoginUserFromToken(String token) throws BaseException {return JwtHelper.getLoginUserFromToken(token, authTokenProperties.getPubKey());}
}
  • 10)创建配置类AuthTokenConfiguration,使用@Bean注解注入TokenUtils
package com.itweid.jjwt.config;import com.itweid.jjwt.utils.TokenUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;@EnableConfigurationProperties(value = {AuthTokenProperties.class,
})
public class AuthTokenConfiguration {@Beanpublic TokenUtils getTokenUtils(AuthTokenProperties authTokenProperties) {return new TokenUtils(authTokenProperties);}
}
  • 11)定义注解@EnableAuthToken,用于启动认证服务
package com.itweid.jjwt.config;import org.springframework.context.annotation.Import;import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(AuthTokenConfiguration.class)
@Documented
@Inherited
public @interface EnableAuthToken {
}
  • 12)创建UserController类,实现登录功能
package com.itweid.jjwt.controller;import com.itweid.jjwt.pojo.LoginUser;
import com.itweid.jjwt.pojo.Token;
import com.itweid.jjwt.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate TokenUtils tokenUtils;//用户登录功能,如果登录成功则签发jwt令牌给客户端@GetMapping("/login")public Token login(){String userName = "admin";String password = "admin123";//查询数据库进行用户名密码校验...//如果校验通过,则为客户端生成jwt令牌LoginUser loginUser = new LoginUser();loginUser.setUserId(1L);loginUser.setAccount(userName);loginUser.setName(userName);loginUser.setTelephone("18922102545");Token token = tokenUtils.generateLoginUserToken(loginUser, null);//实际应该是在过滤器中进行jwt令牌的解析LoginUser userInfo = tokenUtils.getLoginUserFromToken(token.getToken());System.out.println(userInfo);return token;}
}
  • 13)创建启动类JjwtApp,添加@EnableAuthToken注解
package com.itweid.jjwt;import com.itweid.jjwt.config.EnableAuthToken;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableAuthToken
public class JjwtApp {public static void main(String[] args) {SpringApplication.run(JjwtApp.class, args);}
}
  • 14)启动项目,在浏览器访问http://127.0.0.1:8080/user/login

可见,jwt令牌已经生成,且可以成功解析。后续调用服务的其他请求,只需要将该令牌通过请求头传递到后端服务即可。

本节完,更多内容查阅:后台管理系统的通用权限解决方案

延伸阅读:后台管理系统的通用权限解决方案(八)认证机制介绍、JWT介绍与jjwt框架的使用

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国考报名照片无法使用照片审核工具上传失败的解决办法

国考报名过程中&#xff0c;照片审核是至关重要的一步&#xff0c;但许多考生在上传照片时遇到了难题&#xff0c;导致无法继续报名&#xff0c;从而影响抢考场位置&#xff0c;下面就介绍如何快速完成照片处理、审核和上传过审的技巧。 一、国考报名照片基本要求首先&#xff…

vue中如何为不同功能设置不同的默认打印设置(设置不同的打印机)

浏览器自带的window.print 功能较简单&#xff0c;这里使用LODOP露肚皮打印 以下是vue2示例&#xff1a; 从官网中下载Lodop和C-Lodop官网主站安装包并安装到本地电脑可以全局搜索电脑找到安装文件LodopFuncs.js&#xff0c;也可以直接复制我贴出来的文件 //用双端口加载主JS…

数据库管理系统的ACID都各自是什么?

本文基于DBMS中ACID属性的概念&#xff0c;这些属性保证了数据库中执行事务时保持数据一致性、完整性和可靠性所。事务是访问并可能修改数据库内容的单一逻辑工作单元。交易使用读写操作访问数据。为了保持数据库的一致性&#xff0c;在事务前后&#xff0c;遵循某些属性。这些…

ssm基于vue搭建的新闻网站+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 [2 系统…

OB_GINS_day3

这里写目录标题 实现当前状态初始化实现预积分的初始化由于此时preintegration_options 是3&#xff08;也就是考虑odo以及earth rotation&#xff09;为预积分的容器添加需要积分的IMU积分因子接下来是添加新的IMU到preintegration中 实现当前状态初始化 这个state_curr的主要…

如何优化kafka和mysql处理百万级消息计算和落库

一.业务场景 最近业务需要&#xff0c;做了性能优化操作。百万级消息在kafka中秒级传输。cpu密集计算分钟级完成&#xff0c;然后在mysql中秒级落库.模型cpu计算提高了1倍&#xff0c;落表速度提高了5倍&#xff0c;2分钟内完成. 如下序列图&#xff1a; 业务系统A发送千级别…

深度学习基础知识-Batch Normalization(BN)超详细解析

一、背景和问题定义 在深层神经网络&#xff08;Deep Neural Networks, DNNs&#xff09;中&#xff0c;层与层之间的输入分布会随着参数更新不断发生变化&#xff0c;这种现象被称为内部协变量偏移&#xff08;Internal Covariate Shift&#xff09;。具体来说&#xff0c;由…

NLP算法工程师精进之路:顶会论文研读精华

1.学术能力培养 全部论文资料下载&#xff1a; 将论文和 GitHub 资源库匹配 papers with code https://paperswithcode.com/OpenGitHub 新项目快报Github pwc&#xff1a;https://github.com/zziz/pwc GitXiv&#xff1a;http://www.gitxiv.com/ 文章撰写 Overleaf [Autho…

从倍压整流到二极管钳位与限幅

何为倍压整流&#xff1f;这里直接引用“百度百科”解释&#xff0c;如下述。 在一些需用高电压、小电流的地方&#xff0c;常常使用倍压整流电路。倍压整流&#xff0c;可以把较低的交流电压&#xff0c;用耐压较高的整流二极管和电容器&#xff0c;“整”出一个较高的直流电…

Java项目实战II基于Java+Spring Boot+MySQL的工程教育认证的计算机课程管理平台(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着工程教…

uniapp开发小程序【简单的实现点击下拉选择性别功能】

一、展示效果 二、代码 <template><view><view class="form_box"><view class="item"

硅谷甄选(9)SKU模块

SKU模块 8.1 SKU静态 <template><el-card><el-table border style"margin: 10px 0px"><el-table-column type"index" label"序号" width"80px"></el-table-column><el-table-columnlabel"名称…

Flutter Color 大调整,需适配迁移,颜色不再是 0-255,而是 0-1.0,支持更大色域

在之前的 3.10 里&#xff0c; Flutter 的 Impeller 在 iOS 上支持了 P3 广色域图像渲染&#xff0c;但是当时也仅仅是当具有广色域图像或渐变时&#xff0c;Impeller 才会在 iOS 上显示 P3 的广色域的颜色&#xff0c;而如果你使用的是 Color API&#xff0c;会发现使用的还是…

动态威胁场景下赋能企业安全,F5推出BIG-IP Next Web应用防火墙

许多企业正面临由混合和多云环境运营复杂性所引发的危机&#xff0c;它们普遍耗巨资于物理和虚拟设备的持续维护、修补和升级上&#xff0c;而针对不同云环境下的应用部署则需要特有的技能来管理众多繁杂的工具和服务。为助力企业应对上述挑战&#xff0c;F5公司发布了BIG-IP N…

如何用Python同时抓取多个网页:深入ThreadPoolExecutor

背景介绍 在信息化时代&#xff0c;数据的实时性和获取速度是其核心价值所在。对于体育赛事爱好者、数据分析师和投注行业而言&#xff0c;能否快速、稳定地抓取到实时比赛信息显得尤为重要。特别是在五大足球联赛中&#xff0c;能够在比赛进行时获得比分、控球率等实时数据&a…

(转载)Tools for Learning LLVM TableGen

前提 最近在学习有关llvm的东西&#xff0c;其中TableGen占了一部分&#xff0c;所以想特意学习下TableGen相关的语法。这里找到了LLVM官网的一篇介绍TableGen的博客&#xff0c;学习并使用机器翻译为中文。在文章的最后也添加了一些学习TableGen的资源。 原文地址&#xff1…

LARGE SCALE GAN TRAINING FORHIGH FIDELITY NATURAL IMAGE SYNTHESIS

ABSTRACT 尽管最近在生成图像建模方面取得了进展&#xff0c;但成功地从复杂的数据集(如ImageNet)生成高分辨率、多样化的样本仍然是一个难以实现的目标。为此&#xff0c;我们在迄今为止尝试的最大规模上训练生成对抗网络&#xff0c;并研究这种规模特有的不稳定性。我们发现…

组队学习专用——task05

目录 一、基本原理 1. 决策树的基本思想 2. 决策树划分过程中可能遇到的特殊情况 (1) 单一类别终止&#xff1a; (2) 属性用尽&#xff1a; (3) 样本空缺&#xff1a; 3. 决策树的结构 二、信息量、信息熵 1. 信息量 2. 信息熵 三、决策树 1. ID3 决策树&#xff08…

Linux RAID 技术详解:原理、配置、管理及故障处理

本文档深入探讨 Linux 软件 RAID 技术&#xff0c;涵盖 RAID 原理、各种 RAID 级别、mdadm 命令详解、配置步骤、管理方法以及高级故障处理和性能调优策略。 一、 RAID 原理与架构 RAID (Redundant Arrays of Independent Disks&#xff0c;独立磁盘冗余阵列) 技术并非单一技…

「C/C++」C/C++标准库 之 <cstring> 字符串操作库

✨博客主页何曾参静谧的博客📌文章专栏「C/C++」C/C++程序设计📚全部专栏「VS」Visual Studio「C/C++」C/C++程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid函数说明目…