emqx連接啟用jwt令牌認證 jwt令牌 概述 JWT 即 JSON Web Tokens 是一種開放的,用於在兩方之間安全地表示聲明的行業標準的方法(RFC 7519)。 組成 令牌的形式 xxx.yyy.zzz eyJhbGciOiJIUzI1NiJ9 .eyJleHAiOjE2NjU0Nzc ...
emqx連接啟用jwt令牌認證
jwt令牌
概述
JWT 即 JSON Web Tokens
是一種開放的,用於在兩方之間安全地表示聲明的行業標準的方法(RFC 7519)。
組成
令牌的形式 xxx.yyy.zzz
eyJhbGciOiJIUzI1NiJ9
.eyJleHAiOjE2NjU0Nzc4NjEsInVzZXIiOiJtcXR0LWNsaWVudCIsImlhdCI6MTY2NTQ3Njg2MX0
.S9ZrrAk2zmUC2zQ7YNcGwhojLOKV5Bhe3zrMv6rQuzE
由三部分組成,先後分別為HEADER、PAYLOAD、VERIFY SIGNATURE
簡單的說,xxx和yyy是對JSON字元串進行base64加密得到,
zzz是由“xxx.yyy”加密得到,最後組裝成 xxx.yyy.zzz
HEADER
HEADER(頭部)由 ALGORITHM(演算法) 和 TOKEN TYPE(令牌類型) 組成
{
"alg": "HS256",
"typ": "JWT"
}
xxx由HEADER使用Base64加密得到
alg : 表示簽名的演算法
typ : 表示令牌的類型
PAYLOAD
PAYLOAD(負載)存放一些用戶信息,但不能存放敏感信息,因為負載中的信息是公開的
yyy由PAYLOAD使用Base64加密得到
VERIFY SIGNATURE
VERIFY SIGNATURE(驗證簽名)
zzz由前兩部分使用簽名加密得到,即對 xxx.yyy 加密,中間連接的“.”是需要的
生成JWT
依賴
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
代碼
api使用方式是生成JwtBuilder對象 然後調用compact()方法,就能得到JWT.JWT主要由三部分組成,那麼代碼中同理需要對三部分進行構造,使用api時,主要是對PAYLOAD和VERIFY SIGNATURE進行賦值.
Instant now = Instant.now();
Map<String, Object> claims = new HashMap<>();
claims.put("user", "mqtt-client");
String compact = Jwts.builder()
.setClaims(claims) // 自定義聲明
.setIssuedAt(Date.from(now)) // 對標準中的聲明賦值,設置簽發時間
.setExpiration(Date.from(now.plusSeconds(1000))) // 對標準中的聲明賦值,設置過期時間
.signWith(SignatureAlgorithm.HS256, "NmVlR3l2T3BiQnBXMi9veVBlcTZWaEpES09XTzdoWnM=") // 設置簽名
.compact();
System.out.println(compact);
tips
- 值得註意的一點是:不要在 setXxx(標準中的聲明) 之後調用 setClaims,因為這兩個方法會覆蓋所有已設置的聲明
- PAYLOAD可以分為payload和claims,但是兩者既不能都為空也不能都存在,同時只能存在一個,否則將會報錯.
- 可以不手動設置HEADER,api中會自動設置,當然,自己手動設置HEADER屬性也可以
- HEADER中的alg會隨構造的簽名自動變更
- 關於預設的claims
根據RFC 7519協議標準 我們獲取到JWT標準中claims的欄位,這些欄位是可選的
1. iss :Issuer,頒發者
2. sub : Subject,主題
3. aud : Audience,受眾
4. exp :Expiration Time,過期時間
5. nbf :Not Before,不能被接受處理的時間
6. iat :Issued At,發佈時間
7. jti :JWT ID
這些claims欄位可以根據需要去設置,也可以自己定義claim
emqx的安裝
根據環境自己選擇下載
tips
- 如果連接不上服務,建議查看8083埠是否打開
- 如果dashborad無法打開,建議查看18083埠是否打開
hmac-based方式驗證
概述
emqx中hmac-based方式,表明 JWT 將使用對稱密鑰生成簽名和校驗簽名(支持 HS256、HS384 和 HS512 演算法),上述的JWT令牌使用的是SignatureAlgorithm.HS256,使用該方式驗證,上述代碼可以直接使用
HS256("HS256", "HMAC using SHA-256", "HMAC", "HmacSHA256", true)
開啟驗證
- Secret,用於校驗簽名的密鑰,與生成簽名時使用的密鑰相同
- Secret Base64 Encode,表明 Secret 是否經過 Base64 加密,即 EMQX 在使用 Secret 校驗簽名時是否需要先對其進行 Base64 解密
public-key方式驗證
概述
emqx中public-key方式,表明 JWT 使用私鑰生成簽名,需要使用公鑰校驗簽名(支持 RS256、RS384、RS512、ES256、ES384 和 ES512 演算法),對於生成的JWT令牌來說,加密方式我這裡換成了RSA,即SignatureAlgorithm.RS256
RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "RSA", "SHA256withRSA", true)
其原理是對JWT令牌使用私鑰加簽,然後將公鑰配置在emqx上,連接時用emqx中的公鑰驗簽,防止信息被篡改
開啟驗證
- Public Key,指定用於校驗簽名的 PEM 格式的公鑰
PEM格式的公鑰私鑰生成
首先,需要在windows上安裝openssl,然後通過指令生成pem格式文件
openssl生成私鑰命令: openssl genrsa -out rsa_private_key.pem 1024
openssl生成公鑰命令: openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
PEM格式的私鑰Java代碼中是沒辦法直接使用的,需要手動或者通過方法變成連續的字元串
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMGL0LhjNqcK32eTHLrmJovihQjIGYJrqw+GsAwgQxLq2SUZxEkbNNOK8OnR5S8g3PUdHraqWlthiLWLfZB3HjsIhq7if9giln9NkCs8hrbIxaghJTB3zo/L7+Bq2eL3zx5ke9ExceG9Xb7d5RCQ1d/xmzKNZqgC0tOGiiaLrU89AgMBAAECgYBhCNDu8MbgvqG80tOvnF2s+jdKbM/lREex9AvlOHOIU3fkkuOG5333pQwdnh7yHt7IgP36BLRiZibdJf8g46eif+Azf7nmH9fW4tQagdjoVoZGz+9Vp9m2ERRsy7Po50d4C5WQdKbxWiSE6qTWtrqIxpZCGkhPyuWsPaYNTQ2TXQJBAOSM1wFtXD3ivSS+SjgTessQdWHaK/xRvN+glr6JJhzK0Tl6xb8IftFJjBi4RY3e1eAciYVhnTDpQfhKGrRumVMCQQDYyrfldKPxXwWelAVbSAepOrU+Iod0DUKpCRS83dGMQFLI/fmAdNL2AY2drr3w6xdeAWTAagB4sKzWoyEMShMvAkEAr42PSUVbaR3U83hHQjOUSo5l27fduX5/eba8k7Z9U/hmJaSsaER6RQAdYI+KvaLA3diNuap1N7C0P6eMQ7QAiQJBAICYh0shzFnSLsgpL6A88uZsf7Qy0TyC3SbdzyJVRga25SR6mvSa18S7mSCO1fbBzSOjGfuVJWByFKRhMapTilsCQQCaVsZ/2QrlzeHaAfWbMSVi8ml3JlF1nCOyiNtypNJB+HXXrE6SJc3vRnwPIku1N6uduQF2W0ypykCzDdcqGkuF
PEM格式中帶有換行符,處理時需要註意,此時連接的字元串就位私鑰
代碼
package com.mio.mqtt.util;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import sun.misc.BASE64Decoder;
import java.security.KeyFactory;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JWTUtils {
public static void main(String[] args) {
Instant now = Instant.now();
Map<String, Object> claims = new HashMap<>();
claims.put("user", "mqtt-client");
String privateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMGL0LhjNqcK32eTHLrmJovihQjIGYJrqw+GsAwgQxLq2SUZxEkbNNOK8OnR5S8g3PUdHraqWlthiLWLfZB3HjsIhq7if9giln9NkCs8hrbIxaghJTB3zo/L7+Bq2eL3zx5ke9ExceG9Xb7d5RCQ1d/xmzKNZqgC0tOGiiaLrU89AgMBAAECgYBhCNDu8MbgvqG80tOvnF2s+jdKbM/lREex9AvlOHOIU3fkkuOG5333pQwdnh7yHt7IgP36BLRiZibdJf8g46eif+Azf7nmH9fW4tQagdjoVoZGz+9Vp9m2ERRsy7Po50d4C5WQdKbxWiSE6qTWtrqIxpZCGkhPyuWsPaYNTQ2TXQJBAOSM1wFtXD3ivSS+SjgTessQdWHaK/xRvN+glr6JJhzK0Tl6xb8IftFJjBi4RY3e1eAciYVhnTDpQfhKGrRumVMCQQDYyrfldKPxXwWelAVbSAepOrU+Iod0DUKpCRS83dGMQFLI/fmAdNL2AY2drr3w6xdeAWTAagB4sKzWoyEMShMvAkEAr42PSUVbaR3U83hHQjOUSo5l27fduX5/eba8k7Z9U/hmJaSsaER6RQAdYI+KvaLA3diNuap1N7C0P6eMQ7QAiQJBAICYh0shzFnSLsgpL6A88uZsf7Qy0TyC3SbdzyJVRga25SR6mvSa18S7mSCO1fbBzSOjGfuVJWByFKRhMapTilsCQQCaVsZ/2QrlzeHaAfWbMSVi8ml3JlF1nCOyiNtypNJB+HXXrE6SJc3vRnwPIku1N6uduQF2W0ypykCzDdcqGkuF";
try {
// 獲取秘鑰
BASE64Decoder base64Decoder=new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(privateKey);
KeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String compact = Jwts.builder()
.setClaims(claims) // 自定義聲明
.setIssuedAt(Date.from(now)) // 對標準中的聲明賦值,設置簽發時間
.setExpiration(Date.from(now.plusSeconds(1000))) // 對標準中的聲明賦值,設置過期時間
.signWith(SignatureAlgorithm.RS256, keyFactory.generatePrivate(spec)) // 設置簽名
.compact();
System.out.println(compact);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
本文來自博客園,作者:狸子橘花茶,轉載請註明原文鏈接:https://www.cnblogs.com/yusishi/p/16519273.html