前言

说说JWT,先说下互联网服务常见的两种用户认证方式:

session认证与Token认证

session认证

传统的Session认证的大体流程可以表示为用户提供用户名和密码登录后由服务器存储一份用户登录信息并传递给浏览器保存为Cookie,并在下次请求中根据Cookie来识别用户,但这种方式缺陷明显:

  • Session都是保存在内存中,随着认证用户的增多,服务端的开销明显增大
  • 保存在内存中的Session限制了分布式的应用
  • Cookie容易被截获伪造

Token认证

Token 泛指身份验证时使用的令牌,Token鉴权机制从某些角度而言与Cookie是一个作用,其目的是让后台知道请求是来自于受信的客户端,其通过实现了某种算法加密的Token字符串来完成鉴权工作,其优点在于:

  • 服务器不需要保存 Session 数据(无状态),容易实现扩展
  • 有效避免Cookie被截获引发的CSRF攻击
  • 可以存储一些业务逻辑所必要的非敏感信息
  • 便于传输,其构成非常简单,字节占用小

JWT简介

JWT定义

  • JWT全称为Json web token,也就是 Json 格式的 web token,可以这么理解:
Token // 个人证件
JWT // 个人身份证

JWT数据结构

  • JWT由三段字符串组成,中间用.分隔,如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0.wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
  • JWT 的三个部分依次如下:
Header(头部)// Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
Payload(负载)// Payload 部分是一个 JSON 对象,用来存放实际需要传递的数据
Signature(签名)// Signature 部分是对前两部分的签名,防止数据篡改
  • 第一段字符串Header:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9将其 Base64 解码后得到:
{
"typ": "JWT", // TOKEN TYPE ,token类型
"alg": "HS256" //ALGORITHM,算法 哈希256
}
  • 第二段字符串Payload:eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0
PAYLOAD是数据载体,可以有自定义数据
{
"uid": "1234567890" // 自定义数据
}
  • 第三段字符串Signature:wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
Signature 部分是对前两部分的签名,防止数据篡改。

JWT的类库

  • Java 中的 JWT 有很多类库,关于其优缺点可以在官网查看:https://jwt.io/,这里我们介绍Auth0的JWT的集成使用方式
Auth0 实现的 com.auth0 / java-jwt / 3.3.0
Brian Campbell 实现的 org.bitbucket.b_c / jose4j / 0.6.3
connect2id 实现的 com.nimbusds / nimbus-jose-jwt / 5.7
Les Hazlewood 实现的 io.jsonwebtoken / jjwt / 0.9.0
FusionAuth 实现的 io.fusionauth / fusionauth-jwt / 3.1.0
Vert.x 实现的 io.vertx / vertx-auth-jwt / 3.5.1

具体实现

JWT配置

  • pom.xml
<!-- jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.1</version>
</dependency>
  • application.yml
coisini:
security:
jwt-key: coisini
# 过期时间
token-expired-in: 86400000

JWT工具类

  • JwtUtil.java
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.*; /**
* @Description JWT工具类
* @author coisini
* @date Aug 18, 2021
* @Version 1.0
*/
@Component
public class JwtUtil { /**
* key
*/
private static String jwtKey; /**
* 过期时间
*/
private static Integer expiredTimeIn; /**
* JWT KEY
* @param jwtKey
*/
@Value("${coisini.security.jwt-key}")
public void setJwtKey(String jwtKey) {
JwtUtil.jwtKey = jwtKey;
} /**
* 过期时间
* @param expiredTimeIn
*/
@Value("${coisini.security.token-expired-in}")
public void setExpiredTimeIn(Integer expiredTimeIn) {
JwtUtil.expiredTimeIn = expiredTimeIn;
} /**
* 生成令牌
* @param uid 用户id
* @return
*/
public static String makeToken(Long uid) {
return JwtUtil.getToken(uid);
} /**
* 获取令牌
* @param uid 用户id
* @param scope 权限分级数字
* @return
*/
private static String getToken(Long uid) {
// 指定算法
Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); Map<String, Date> dateMap = JwtUtil.calculateExpiredIssues(); /**
* withClaim() 写入自定义数据
* withExpiresAt() 设置过期时间
* withIssuedAt() 设置当前时间
* sign() 签名算法
*/
return JWT.create()
.withClaim("uid", uid)
.withExpiresAt(dateMap.get("expiredTime"))
.withIssuedAt(dateMap.get("now"))
.sign(algorithm);
} /**
* 获取自定义数据
* @param token
* @return
*/
public static Optional<Map<String, Claim>> getClaims(String token) {
DecodedJWT decodedJWT; // 指定算法
Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey);
JWTVerifier jwtVerifier = JWT.require(algorithm).build(); try {
decodedJWT = jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
return Optional.empty();
} return Optional.of(decodedJWT.getClaims());
} /**
* 验证Token
* @param token
* @return
*/
public static boolean verifyToken(String token) {
try {
Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey);
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
return false;
} return true;
} /**
* 计算过期时间
* @return
*/
private static Map<String, Date> calculateExpiredIssues() {
Map<String, Date> map = new HashMap<>();
Calendar calendar = Calendar.getInstance();
Date now = calendar.getTime();
calendar.add(Calendar.SECOND, JwtUtil.expiredTimeIn);
// 当前时间
map.put("now", now);
// 过期时间
map.put("expiredTime", calendar.getTime());
return map;
} }

测试接口

  • JwtController.java
@RestController
@RequestMapping("/jwt")
public class JwtController { /**
* 获取Token
* @param id
* @return
*/
@GetMapping(value = "/get")
public String getToken(@RequestParam Long id) {
return JwtUtil.makeToken(id);
} /**
* 验证Token
* @param token
* @return
*/
@PostMapping("/verify")
public Map<String, Boolean> verify(@RequestParam String token) {
Map<String, Boolean> map = new HashMap<>();
Boolean valid = JwtUtil.verifyToken(token);
map.put("is_valid", valid);
return map;
} }
  • 测试结果

  • JWT生成的Token应该放在请求头内来传输,后端统一拦截验证,这里留在下篇文章吧。。。

- End -



梦想是咸鱼
关注一下吧

SpringBoot - 集成Auth0 JWT的更多相关文章

  1. SpringBoot 集成SpringSecurity JWT

    目录 1. 简介 1.1 SpringSecurity 1.2 OAuth2 1.3 JWT 2. SpringBoot 集成 SpringSecurity 2.1 导入Spring Security ...

  2. SpringBoot集成Security,JWT,Swagger全分析

    GitHub地址: https://github.com/li-jun0201/springsecuritydemo本项目采用SpringBoot1.5.9, SpringSecurity,JWT, ...

  3. SpringBoot集成JWT实现token验证

    原文:https://www.jianshu.com/p/e88d3f8151db JWT官网: https://jwt.io/ JWT(Java版)的github地址:https://github. ...

  4. SpringBoot集成JWT 实现接口权限认证

    JWT介绍 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的, 特别适用于分布式站点 ...

  5. 【springBoot】springBoot集成redis的key,value序列化的相关问题

    使用的是maven工程 springBoot集成redis默认使用的是注解,在官方文档中只需要2步; 1.在pom文件中引入即可 <dependency> <groupId>o ...

  6. SpringBoot集成security

    本文就SpringBoot集成Security的使用步骤做出解释说明.

  7. springboot集成Actuator

    Actuator监控端点,主要用来监控与管理. 原生端点主要分为三大类:应用配置类.度量指标类.操作控制类. 应用配置类:获取应用程序中加载的配置.环境变量.自动化配置报告等与SpringBoot应用 ...

  8. SpringBoot集成Shiro并用MongoDB做Session存储

    之前项目鉴权一直使用的Shiro,那是在Spring MVC里面使用的比较多,而且都是用XML来配置,用Shiro来做权限控制相对比较简单而且成熟,而且我一直都把Shiro的session放在mong ...

  9. SpringBoot集成redis的key,value序列化的相关问题

    使用的是maven工程 springBoot集成redis默认使用的是注解,在官方文档中只需要2步; 1.在pom文件中引入即可 <dependency> <groupId>o ...

随机推荐

  1. Docker:Docker部署postgresql数据库

    环境 Centos-7  Postgresql-10 docker-19 yum加载Postgresql yum install https://download.postgresql.org/pub ...

  2. 其他:什么是元数据?(Metadata)?

    元数据     任何文件系统中的数据分为数据和元数据.数据是指普通文件中的实际数据,而元数据指用来描述一个文件的特征的系统数据,诸如访问权限.文件拥有者以及文件数据块的分布信息(inode...)等等 ...

  3. Java:jar包与war包的差异

    一般将项目分为两层:服务层和表现层(视图层),通常我们把服务层打包成jar,而把视图层的包打成war包. 仔细对比可以发现: jar包中包含了你写程序的所有服务或者第三方类库,它通常是作为幕后工作者, ...

  4. Linux安装mysql5.7版本

    1.linux安装mysql5.7顺序 ①mysqladmin –version 查看版本号 ②mysql5.7安装在linux中需要先初始化 Mysqld –initialize –user=mys ...

  5. 在spring boot使用总结(九) 使用yaml语言来写配置文件

    yaml是专门用来写配置文件的语言.使用yaml来写配置文件扩展性比较强而且十分方便.spring boot支持使用yaml语言来写配置文件,使用snakeyaml库来读取配置文件.spring bo ...

  6. 前端-HTML标签

    1.<p></p>段落标签 <p>别在最该拼搏的年纪选择稳定,世界上最大的不变是改变,只有每天进步,才能拥抱生命的无限可能!</p> 2.</b& ...

  7. c语言:getch() getchar()

    1.getchar();从键盘读取一个字符并输出,该函数的返回值是输入第一个字符的ASCII码:若用户输入的是一连串字符,函数直到用户输入回车时结束,输入的字符连同回车一起存入键盘缓冲区.若程序中有后 ...

  8. Ubuntu18.04 安装opensips,实现局域网内sip语音视频通话

    Ubuntu18.04直接安装opensips 本人实践亲测有效,用docker安装opensips尝试多次均无法连接mysql数据库,故舍弃,直接在主机上安装opensips 部分内容参考自:htt ...

  9. Swift-为什么String转换Int的结果是nil

    摘要 知其然,更要知其所以然.前段时间用 String 转换 Int 处理时,发现一种情况返回 nil,就换成 String 转换 Double 的方式处理.今天就要来看看这种返回 nil 的情况是怎 ...

  10. 祝贺|合肥.NET俱乐部第二期技术沙龙活动圆满成功

    热烈祝贺合肥.NET俱乐部第二期技术沙龙圆满成功,感恩参与活动的每一位小伙伴!正是因为有你们才促成了这次聚会的成功.现对此次活动进行简单回顾并附上精彩的活动图片,每一位参与活动者名单,以及此次活动讲师 ...