接口地址
- 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";