添加依赖

<dependencies>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<!--注意这里要加上这些,不然证书无法加载-->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.jks</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.jks</include>
</includes>
</resource>
</resources> </build>

普通方式创建jwt令牌

package com.example.demo;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date; /**
* @author liuyalong
*/
public class JwtTest { public static void main(String[] args) {
final String keyStr = "4379";
Key key = new SecretKeySpec(keyStr.getBytes(), SignatureAlgorithm.HS512.getJcaName()); // expire_time为token有效时长, 单位毫秒
final long expire_time =10000;
Date expiresDate = new Date(System.currentTimeMillis() + expire_time); //生成jwt令牌
JwtBuilder jwtBuilder = Jwts.builder()
//设置jwt编码
.setId("66")
//设置jwt主题
.setSubject("我是主题")
//设置jwt签发日期
.setIssuedAt(new Date())
.claim("a", "admin")
.claim("b", "aaaa")
.claim("c", "yalong")
//设置jwt的过期时间,好像必须在claim后面
.setExpiration(expiresDate)
//注意,这里的密码应该使用Key类型,不应使用String类型
//如果使用String类型,比如4379123加密,那么解密使用4379也可以解开,
// 因为这个String类型是base64EncodedSecretKey
.signWith(SignatureAlgorithm.HS256, key); //生成jwt
String jwtToken = jwtBuilder.compact();
System.out.println(jwtToken); //解析jwt,得到其内部的数据
Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody();
System.out.println(claims.get("exp"));
System.out.println(claims);
}
}

使用keytool生成证书

keytool -genkeypair -alias test -keyalg RSA -keypass yalong -keystore "D://yalong.jks" -storepass yalong -validity 3650 -dname "CN=localhost,OU=localhost,O=localhost,L=SH,ST=SH,C=CN" -storetype pkcs12

注意:这里有个大坑,keypass 必须和storepass一样,不然私钥解不开,或许是keytool的原因造成的

  • alias:密钥的别名
  • keyalg:使用的hash算法
  • keypass:密钥的访问密码
  • keystore:密钥库文件名,yalong.jks保存了生成的证书
  • storepass:密钥库的访问密码
  • validity 3650 : 有效期10年
  • dname :证书的相关信息,
    • CN:名字与形式
    • OU:组织单位名称
    • O:组织机构名称
    • L:城市信息
    • ST:省份信息
    • C:国家信息

查看密钥库

keytool -list -keystore "D://yalong.jks" -storepass liuyalong

导出公钥证书文件.cer

keytool -export -alias test -keystore "D://yalong.jks" -file "D://publicKey.cer" -storepass yalong

使用密钥对生成JWT并加密解密

使用私钥生成JWT令牌,使用公钥解密,公钥可以公开,私钥留在授权服务里,公钥可以导出,私钥不可以导出

package com.example.demo;

import java.io.FileInputStream;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory; /**
* @author liuyalong
*/
public class GetRsaKey { public static void main(String[] args) throws Exception {
//证书库文件路径
// 这里使用ClassPathResource路径,所以不带D:/
String storePath = "yalong.jks"; //这个路径用来获取私钥
String storePath1 = "D:/yalong.jks"; //公钥证书文件路径
//从keystore 导出公钥证书文件.cer,命令如下
//keytool -export -alias test -keystore "D://yalong.keystore" -file "D://publicKey.cer"
String cerPath = "D:/publicKey.cer"; //证书别名
String alias = "test";
//证书库密码
String storePw = "yalong";
//证书密码
String keyPw = "yalong";
String publicKey = getPublicKey(cerPath);
String privateKey = getPrivateKey(storePath1, alias, storePw, keyPw); System.out.println("从证书获取的公钥为:" + publicKey);
System.out.println("从证书获取的私钥为:" + privateKey); Map<String, String> map = new HashMap<>();
map.put("company", "honbow");
map.put("address", "shenzhen");
String jwt = createJwt(storePath, alias, storePw, keyPw, map);
System.out.println("生成JWT为:" + jwt); String s = parseJwt(jwt, publicKey);
System.out.println("校验后:" + s);
} /**
* 从公钥证书中获取公钥
*
* @param cerPath 公钥证书的路径
*/
private static String getPublicKey(String cerPath) throws Exception {
CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
FileInputStream fis = new FileInputStream(cerPath);
// X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(fis);
Certificate cert = certificatefactory.generateCertificate(fis);
PublicKey pk = cert.getPublicKey();
String pkString = new Base64().encodeToString(pk.getEncoded());
//这里需要拼接开头和结尾,不然无法解析出来结果,可能有其他验证方法
return "-----BEGIN PUBLIC KEY-----" + pkString + "-----END PUBLIC KEY-----";
} private static String getPublicKey(String cerPath, String instanceType) throws Exception {
CertificateFactory certificatefactory = CertificateFactory.getInstance(instanceType);
FileInputStream fis = new FileInputStream(cerPath);
Certificate cert = certificatefactory.generateCertificate(fis);
PublicKey pk = cert.getPublicKey();
return new Base64().encodeToString(pk.getEncoded());
} /**
* @param storePath 证书库的路径
* @param alias 证书别名,创建时指定的
* @param storePw 访问证书库的密码
* @param keyPw 访问证书的密码
* @param JwtMap 需要设置进Jwt的内容
* @return jwt 字符串
*/
private static String createJwt(String storePath,
String alias,
String storePw,
String keyPw,
Map<String, String> JwtMap) { ClassPathResource classPathResource = new ClassPathResource(storePath); KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(classPathResource, keyPw.toCharArray()); KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, storePw.toCharArray()); //将当前的私钥转换为rsa私钥
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
Jwt jwt = JwtHelper.encode(JSON.toJSONString(JwtMap), new RsaSigner(rsaPrivateKey));
return jwt.getEncoded();
} /**
* 生成私钥
*
* @param storePath 证书库的路径
* @param alias 证书别名,创建时指定的
* @param storePw 访问证书库的密码
* @param keyPw 访问证书的密码
*/
private static String getPrivateKey(String storePath, String alias, String storePw, String keyPw) throws Exception {
FileInputStream is = new FileInputStream(storePath);
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(is, storePw.toCharArray());
is.close();
PrivateKey key = (PrivateKey) ks.getKey(alias, keyPw.toCharArray());
return new Base64().encodeToString(key.getEncoded());
} private static String getPrivateKey(String storePath, String alias, String storePw, String keyPw, String storeType) throws Exception {
FileInputStream is = new FileInputStream(storePath);
KeyStore ks = KeyStore.getInstance(storeType);
ks.load(is, storePw.toCharArray());
is.close();
PrivateKey key = (PrivateKey) ks.getKey(alias, keyPw.toCharArray());
return new Base64().encodeToString(key.getEncoded());
} /**
* @param jwt jwt字符串
* @param publicKey 公钥
* @return 解密后的字符串token
*/
private static String parseJwt(String jwt, String publicKey) { Jwt token = JwtHelper.decodeAndVerify(jwt, new RsaVerifier(publicKey)); return token.getClaims();
}
}

RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?

  • 既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。

注:

JWT保证的是数据传输过程中的完整性而不是机密性。

由于payload是使用base64url编码的,所以相当于明文传输,如果在payload中携带了敏感信息(如存放密钥对的文件路径),单独对payload部分进行base64url解码,就可以读取到payload中携带的信息。

Jwt令牌创建的更多相关文章

  1. Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

    概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 .JWT 的使用,这一节要求对 OAuth2.JWT 有了解,若不清楚,先移步到下面两篇提前了解下. Spring Bo ...

  2. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_13-SpringSecurityOauth2研究-JWT研究-生成JWT令牌&验证JWT令牌

    生成jwt需要用私钥来签名.在Auth认证服务下创建测试类 创建密钥工厂,构造函数需要的参数 获取私钥 有了私钥就可以生成JWT令牌 使用jwtHelper是spring security里面的类 e ...

  3. 什么是JWT令牌认证?

    当下,JWT(JSON Web Token)令牌认证已经变得越来越流行.本文主要介绍JWT令牌认证与传统的Session会话认证机制的区别. 为什么需要认证? HTTP是一种无状态协议,那就意味着当前 ...

  4. 畅购商城(八):微服务网关和JWT令牌

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 畅购商城(一):环境搭建 畅购商 ...

  5. Spring Security OAuth2.0认证授权三:使用JWT令牌

    Spring Security OAuth2.0系列文章: Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二: ...

  6. JWT令牌简介及demo

    一.访问令牌的类型 二.JWT令牌 1.什么是JWT令牌 ​ JWT是JSON Web Token的缩写,即JSON Web令牌,是一种自包含令牌. JWT的使用场景: 一种情况是webapi,类似之 ...

  7. spring security oauth2搭建resource-server demo及token改造成JWT令牌

    我们在上文讲了如何在spring security的环境中搭建基于oauth2协议的认证中心demo:https://www.cnblogs.com/process-h/p/15688971.html ...

  8. 微服务架构 | 7.2 构建使用 JWT 令牌存储的 OAuth2 安全认证

    目录 前言 1. JWT 令牌存储基础知识 1.1 JSON Web Token 2. 构建使用 JWT 令牌存储的 OAuth2 服务器 2.1 引入 pom.xml 依赖文件 2.2 创建 JWT ...

  9. 阶段5 3.微服务项目【学成在线】_day18 用户授权_03-方法授权-jwt令牌包含权限

    修改认证服务的UserDetailServiceImpl类,下边的代码中 permissionList列表中存放了用户的权限, 并且将权限标识按照中间使用逗号分隔的语法组成一个字符串,最终提供给Spr ...

随机推荐

  1. Microsoft Visual C++ 2005 SP1无法安装

    安装时出现需要Microsoft Visual C++ 2005 Redistributble对话框, 里面说Command line option syntax error . Type Comma ...

  2. 转载 Web前端开发 HTML设计 经验与技巧总结

    文章目录1.限制input 输入框只能输入纯数字.限制长度.默认显示文字2.input输入框自动获取焦点3.用CSS让背景有透明度文字不变4.a标签禁止点击5.文字两种居中对齐6.设置一个元素一直在页 ...

  3. 07 . 前端工程化(ES6模块化和webpack打包)

    模块化规范 传统开发模式主要问题 /* 1. 命名冲突 2. 文件依赖 */ 通过模块化解决上述问题 /* 模块化就是把单独的一个功能封装在一个模块(文件)中,模块之间相互隔离, 但是可以通过特定的接 ...

  4. webug第十四关:存储型XSS

    第十四关:存储型XSS 打开发现是评论区 留言加入xss语句

  5. DDBNet:Anchor-free新训练方法,边粒度IoU计算以及更准确的正负样本 | ECCV 2020

    论文针对当前anchor-free目标检测算法的问题提出了DDBNet,该算法对预测框进行更准确地评估,包括正负样本以及IoU的判断.DDBNet的创新点主要在于box分解和重组模块(D&R) ...

  6. Java Web 会话技术总结

    会话技术 会话概念 一次会话中包含多次请求和响应. 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止,一次会话结束. 会话的功能 在一次会话的范围内的多次请求间,共享数据. 会 ...

  7. 如何使用Camtasia进行电脑录制屏幕

    在现在的网络互联网时代,越来越多的人走上了自媒体的道路.有些自媒体人会自己在网络上录制精彩视频,也有一些人会将精彩.热门的电影剪辑出来再加上自己给它的配音,做成大家喜欢看的电影剪辑片段.相信不管大家是 ...

  8. css3系列之过渡transition

    transition 设置变换属性的过渡效果,举个例子,也就是说, 如果从width100px 变成 width200px,要以什么方式进行变换,速度,时间,类型等. transition trans ...

  9. MarkDown学习总结-2020.05.11

    1.使用工具 1.1Typora 官网地址:https://www.typora.io/ 下载链接 2.基础入门 注意: []中的内容则是对应格式的标记符,默认全部标识符后面需要多加一个空格才能生效. ...

  10. markdown语法和数学公式

    目录 Markdown简介 代码块 LaTeX 公式 表格 LaTeX 矩阵公式 Markdown简介 Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格 ...