添加依赖

<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. Cephfs 操作输出到日志查询系统

    前言 文件系统当中如果某些文件不见了,有什么办法判断是删除了还是自己不见了,这个就需要去日志里面定位了,通常情况下是去翻日志,而日志是会进行压缩的,并且查找起来非常的不方便,还有可能并没有开启 这个时 ...

  2. python菜鸟教程学习5: python运算符

    算术运算符: 整除符号//:向下取接近商的整数 加+ 减- 乘* 除/ 取余% 幂** 比较运算符: 等于== 不等于!= 大于> 小于< 大于等于>= 小于等于<= 赋值运算 ...

  3. 通过RayFire为图形添加二次破碎效果

    在完成3D建模之后,RayFire能帮助用户制作多种类型的破碎效果,如均匀碎片.放射状碎片.木碎等效果.另外,用户还可以利用RayFire的碎片选取功能,为图形进行二次破碎,以达到增加局部碎片的效果. ...

  4. 用Camtasia来快速地给视频添加水印

    在日常生活中,视频的流行度越来越高,各种短视频的软件蜂拥上市,所以越来越多的人走上了自媒体的道路,在这条路上,谁的视频更加的精致,谁才能获得更多的关注度,相应的也能增加自己的人气. 但是在制作视频的过 ...

  5. 唯一key的生成规则,可自己视情况改动

    <?php function getMillisecond() { $time = explode ( " ", microtime ()); $time = $time[1 ...

  6. 开始使用 java8 的日期工具类

    例如,现有的类(例如java.util.Date和SimpleDateFormatter)不是线程安全的,这会导致用户潜在的并发问题.而新的LocalDate.LocalDateTime.DateTi ...

  7. java8的lambda表达式

    关于java8的lambda表达式 lambda表达式一般用于接口,因为lambda表达式是函数式编程. 1.有且仅有一个抽象方法被称为函数式接口,函数式接口可以显示的被@FunctionalInte ...

  8. 关于UILabel标签控件的使用小节

    前段时间一直想停下来,总结一下近期在开发中遇到的一些问题顺便分享一下解决问题的思路和方法,无奈人生就像蒲公英,看似自由却身不由己.太多的时间和精力被占用在新项目的开发和之前项目的维护中,总之一句话外包 ...

  9. 记XShell无法连接虚拟机中的Linux,但Linux系统中可以连接外网。

    如题. 原本设置如下: 本地机IP 为192.168.43.XXX VMWare中"虚拟机网络编辑器"中子网设置为192.168.39.0. 虚拟机中IP为192.168.39.1 ...

  10. Python变量引用

    >>>a=3 >>>b=a >>>a=4 >>>b >>>3 >>>List1=[1,2,3 ...