介面地址
- keycloak開放介面地址:/auth/realms/fabao/.well-known/openid-configuration
rsa演算法相關術語
RSA演算法是一種非對稱加密演算法,其安全性基於大整數分解的困難性。在RSA演算法中,有以下幾個關鍵引數:
-
n(模數):n 是一個大整數,通常為兩個大素數 p 和 q 的乘積,即 n = p * q。n 用於生成公鑰和私鑰,並且決定了加密和解密的計算過程。
-
e(公鑰指數):e 是一個與 φ(n) 互質的小整數,其中 φ(n) 是尤拉函式,表示小於 n 且與 n 互質的正整數的個數。e 在加密時使用,作為公鑰的一部分。
-
公鑰:公鑰由 (n, e) 組成,其中 n 是模數,e 是公鑰指數。公鑰用於加密訊息,任何人都可以獲得公鑰進行加密操作。
-
私鑰:私鑰由 (n, d) 組成,其中 n 是模數,d 是私鑰指數。私鑰用於解密已經被公鑰加密的訊息,只有私鑰的持有者才能獲得解密能力。
總結來說,RSA演算法透過公鑰加密、私鑰解密的方式實現資訊的安全傳輸,公鑰用於加密資料,私鑰用於解密資料;反過來,私鑰可以用來生成簽名,而公鑰可以用來驗證簽名的有效性。
RSA和RS256
-
RSA:RSA是一種非對稱加密演算法,可以用於資料的加密和數字簽名。在RSA中,公鑰和私鑰是成對存在的,公鑰用於加密資料或驗證數字簽名,私鑰用於解密資料或生成數字簽名。
-
RS256:RS256是一種基於RSA演算法的數字簽名演算法,其中“RS”代表RSA演算法,“256”表示使用SHA-256雜湊演算法生成摘要。RS256常用於JWT(JSON Web Token)的數字簽名過程中,用於驗證資料的完整性和真實性。
因此,可以說RS256是RSA演算法的一種特定應用,用於數字簽名,並且結合了SHA-256雜湊演算法。RSA演算法還可以用於加密資料等其他用途,而RS256主要用於數字簽名。
獲取keycloak頒發的公鑰
- 從jwks公鑰開放地址獲取公鑰 /auth/realms/fabao/protocol/openid-connect/certs
- 從keycloak後臺獲取公鑰
keycloak中jwt的驗證
- 在客戶端驗證keycloak的token是否在傳輸過程中被篡改,即簽名驗證是否透過
- 下面程式碼中定義了公鑰字串,從開放地址返回的rsa公鑰的n模數和e指數
- 從kecloak認證中心頒發的公鑰字串
- 從現在有keycloak認證中心獲取的jwt字串
// RSA公鑰的模數
String modulus = "yOCNCy8x280...";
// RSA公鑰的指數
String exponent = "AQAB";
// keycloak拿到的公鑰
String publicKeyString = "MIIBIjANBg...B";
String KcJwtToken = "eyJh...";
- 根據公鑰開放地址返回的公鑰資訊n和e來驗證簽名
@Test
public void verifySign() throws Exception {
String[] jwtParts = KcJwtToken.split("\\.");
String header = jwtParts[0];
String payload = jwtParts[1];
// 解碼Base64格式的模數和指數
byte[] decodedModulus = Base64.getUrlDecoder().decode(modulus);// getMimeDecoder()會忽略非Base64字元(如換行符、空格等)
byte[] decodedExponent = Base64.getUrlDecoder().decode(exponent);
// 構建RSA公鑰物件
RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(new BigInteger(1, decodedModulus),
new BigInteger(1, decodedExponent));
// 驗徵RSA簽名
PublicKey publicKey = KeyFactory.getInstance("rsa").generatePublic(publicSpec);
boolean result = RSAUtils.verify(header + "." + payload, publicKey, jwtParts[2]);
System.out.print("驗簽結果:" + result);
}
- 根據keycloak後臺頒發的公鑰字串來驗證簽名
// 根據認證平臺頒發的公鑰字串來驗證簽名
@Test
public void verifyJwtToken() throws Exception {
String[] jwtParts = KcJwtToken.split("\\.");
String header = jwtParts[0];
String payload = jwtParts[1];
String sign = jwtParts[2];
PublicKey publicKey = RSAUtils.getPublicKey(publicKeyString);
boolean result = RSAUtils.verify(header + "." + payload, publicKey, sign);
System.out.print("驗簽結果:" + result);
}
需要注意的是,以上jwt的token簽名使用rs256(SHA256withRSA)演算法生成的簽名,所以本例子都是採用這種簽名演算法實現的,例外,也有h256,h512等雜湊演算法。
keycloak支援的簽名演算法
public static final String RS256 = "SHA256withRSA";
public static final String RS384 = "SHA384withRSA";
public static final String RS512 = "SHA512withRSA";
public static final String HS256 = "HMACSHA256";
public static final String HS384 = "HMACSHA384";
public static final String HS512 = "HMACSHA512";
public static final String ES256 = "SHA256withECDSA";
public static final String ES384 = "SHA384withECDSA";
public static final String ES512 = "SHA512withECDSA";
public static final String PS256 = "SHA256withRSAandMGF1";
public static final String PS384 = "SHA384withRSAandMGF1";
public static final String PS512 = "SHA512withRSAandMGF1";
public static final String AES = "AES";
public static final String SHA256 = "SHA-256";
public static final String SHA384 = "SHA-384";
public static final String SHA512 = "SHA-512";