添加依赖

<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. 怎样禁止Ceph OSD的自动挂载

    前言 本篇来源于群里一个人的问题,有没有办法让ceph的磁盘不自动挂载,一般人的问题都是怎样让ceph能够自动挂载,在centos 7 平台下 ceph jewel版本以后都是有自动挂载的处理的,这个 ...

  2. C函数 printf 拼接字符串

    C函数 printf 拼接字符串 从前学C语言,最常用的函数可能就是 printf 了,但是往往是这样: printf(年龄是:"%d",a); 由于不懂得怎么拼接字符串,有时候只 ...

  3. Docker学习第三天(Docker数据卷管理)

    1.Docker数据卷管理 在Docker中,要想实现数据的持久化(所谓Docker的数据持久化即数据不随着Container的结束而结束),需要将数据从宿主机挂载到容器中.目前Docker提供了三种 ...

  4. 赶紧收藏!这些Java中的流程控制知识你都不知道,你凭什么涨薪?

    Java的流程控制 基础阶段 目录: 用户交互Scanner 顺序结构 选择结构 循环结构 break & continue 练习题 1.Scanner对象 之前我们学的基本语法中并没有实现程 ...

  5. 应聘阿里,字节跳动美团90%会问到的JVM面试题! 史上最全系列!

    Java 内存分配 • 寄存器:程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码.• 静态域:static 定义的静态成员.• 常量池:编译时被确定并保存在 .class 文件中的(f ...

  6. 3dmax利用静止静态对象功能,制作精准击碎效果

    一般情况下,当我们在3D建模中使用RayFire破碎插件来制作一些精准击碎效果时,需要将物体的击中部分定义为休眠对象,将其他未击中的部分定义为静态对象,以实现击中部分出现碎片的效果.但这种方式必须精准 ...

  7. FL Studio 插件使用技巧——Fruity Reeverb 2 (上)

    许多学习FL的用户会发现,自己在听大师的电子音乐作品时都能感受到他们的音乐有一股强大的空间感,有时还能感知到深邃的意境.不少人会因此而疑惑:为什么出自我们之手的音乐就没有这样的效果呢?我们的音乐里到底 ...

  8. Python生成随机测试数据

    前言 安装 pip install Faker 使用 from faker import Faker fake = Faker() name = fake.name() address = fake. ...

  9. 配置Nginx 扩展实现图片剪裁

    在此之前需要安装ngx_http_image_filter_module,如果是采用的Docker的话可以看看我历史文章. 然后修改配置文件,增加几个location模块,配置如下,仅供参考 serv ...

  10. DFS文件服务器实验手册

    基础配置信息清单 计算机名 角色 网络配置 DNS WIN-6E DC 11.1.1.10/24 127.0.0.1 WIN-C4 Node1 11.1.1.20/24 11.1.1.10 WIN-4 ...