package org.keycloak.keys.loader;
import org.jboss.logging.Logger;
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.KeyType;
import org.keycloak.crypto.KeyUse;
import org.keycloak.crypto.KeyWrapper;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.keys.PublicKeyLoader;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.utils.JWKSHttpUtils;
import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.services.util.CertificateInfoHelper;
import org.keycloak.services.util.ResolveRelative;
import org.keycloak.util.JWKSUtils;
import org.keycloak.util.JsonSerialization;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Map;
/**
* @author Marek Posolda
*/
public class ClientPublicKeyLoader implements PublicKeyLoader {
private static final Logger logger = Logger.getLogger(ClientPublicKeyLoader.class);
private final KeycloakSession session;
private final ClientModel client;
private final JWK.Use keyUse;
public ClientPublicKeyLoader(KeycloakSession session, ClientModel client) {
this.session = session;
this.client = client;
this.keyUse = JWK.Use.SIG;
}
public ClientPublicKeyLoader(KeycloakSession session, ClientModel client, JWK.Use keyUse) {
this.session = session;
this.client = client;
this.keyUse = keyUse;
}
@Override
public Map loadKeys() throws Exception {
OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientModel(client);
try {
logger.debugv( "oidc advancedConfig is {0}", JsonSerialization.writeValueAsPrettyString( config ) );
} catch (Exception cause) {
}
if (config.isUseJwksUrl()) {
String jwksUrl = config.getJwksUrl();
jwksUrl = ResolveRelative.resolveRelativeUri(session.getContext().getUri().getRequestUri(), client.getRootUrl(), jwksUrl);
JSONWebKeySet jwks = JWKSHttpUtils.sendJwksRequest(session, jwksUrl);
return JWKSUtils.getKeyWrappersForUse(jwks, keyUse);
} else if (keyUse == JWK.Use.SIG) {
try {
CertificateRepresentation certInfo = CertificateInfoHelper.getCertificateFromClient(client, JWTClientAuthenticator.ATTR_PREFIX);
KeyWrapper publicKey = getSignatureValidationKey(certInfo);
return Collections.singletonMap(publicKey.getKid(), publicKey);
} catch (ModelException me) {
logger.warnf(me, "Unable to retrieve publicKey for verify signature of client '%s' . Error details: %s", client.getClientId(), me.getMessage());
return Collections.emptyMap();
}
} else {
logger.warnf("Unable to retrieve publicKey of client '%s' for the specified purpose other than verifying signature", client.getClientId());
return Collections.emptyMap();
}
}
private static KeyWrapper getSignatureValidationKey(CertificateRepresentation certInfo) throws ModelException {
KeyWrapper keyWrapper = new KeyWrapper();
String encodedCertificate = certInfo.getCertificate();
String encodedPublicKey = certInfo.getPublicKey();
if (encodedCertificate == null && encodedPublicKey == null) {
throw new ModelException("Client doesn't have certificate or publicKey configured");
}
if (encodedCertificate != null && encodedPublicKey != null) {
throw new ModelException("Client has both publicKey and certificate configured");
}
//here ...................
// keyWrapper.setAlgorithm(Algorithm.RS256);
//注意这里
keyWrapper.setAlgorithm(Algorithm.PS256);
keyWrapper.setType(KeyType.RSA);
keyWrapper.setUse(KeyUse.SIG);
String kid = null;
if (encodedCertificate != null) {
X509Certificate clientCert = KeycloakModelUtils.getCertificate(encodedCertificate);
// Check if we have kid in DB, generate otherwise
kid = certInfo.getKid() != null ? certInfo.getKid() : KeyUtils.createKeyId(clientCert.getPublicKey());
keyWrapper.setKid(kid);
keyWrapper.setPublicKey(clientCert.getPublicKey());
keyWrapper.setCertificate(clientCert);
logger.debug("getSignatureValidationKey * * * get the kid"+kid+"keyWrapper"+keyWrapper.toString());
} else {
logger.debugf( "encodedPublicKey is %s", encodedPublicKey );
PublicKey publicKey = KeycloakModelUtils.getPublicKey(encodedPublicKey);
logger.debugv( "public key algo", publicKey.getAlgorithm() );
// Check if we have kid in DB, generate otherwise
kid = certInfo.getKid() != null ? certInfo.getKid() : KeyUtils.createKeyId(publicKey);
keyWrapper.setKid(kid);
//注意这里
keyWrapper.setAlgorithm( Algorithm.PS256 );
keyWrapper.setPublicKey(publicKey);
}
return keyWrapper;
}
}
RSAKey privateKey = new RSAKeyGenerator(2048)
.algorithm(JWSAlgorithm.PS256)
.keyUse(KeyUse.SIGNATURE)
.keyID("client-PS256")
.generate();
RSAKey publicKey = privateKey.toPublicJWK();
私钥
{
"keys": [
{
"p": "77_7i2uGN6RxaCU6m217guw2gdLeknEbi34IeJpvK5xqufrs00aMCqnCXwWAEsqCm3CmITdhTPNZSemETcsouW82NiHQ_cbI7agNpAaTU6kRdzaOVyJSJgs-pmxgFMbgkBmIHZbbtdrpIykTHlhmilPnRhQvwN3N_7eymmbXPe0",
"kty": "RSA",
"q": "nbVbCk7BMP1syPPR0IUbDwYmLkFnUL6TXgXA4o-3IIdP-bFJKc2ONTxtsLl-Q-H2dDKugjHe-AyVvVRmiMUna2VVEUbG3I6z0mvok19fC9Gd7kCalJuXfNBnJVyoJfCfOmDn3RepYUP7mWUAmlbtMxbud0-F90T60vIgewPN7e0",
"d": "COuCJEsUHUcg39kF9S9cTt8GsaxIEP-vqI9GonGz_nC3uBFDRhyqGKj-JWWoG3Vso3i658bnJdMf1aW4KjxJon-D0nfAAZXPUj7OfJZ__D874BKRSg9NqE7uubsU3ByPvLVexqsGAy4tRCM14zwXpNM_YAe0z7c4tmSrDmUdFZUpt8YhL33jPi5KDaxtEdMrbL2OKIdrolJjJnX7loVJcSneM7bXvx-6ieDfO8HgMlmnpik3t_9HVeJ1-o30ndv5KsVG1i7NtTDgAGTqbInHD7WdRLIzgTbXTmoAWY4ccHeDNzh6S_9jKk_sQE9A1oLFUmL-7qtk8qnl9ZBDoxGIYQ",
"e": "AQAB",
"use": "sig",
"kid": "client-PS256",
"qi": "AiADA77A6JGn1iOEd2CM0c17LK6AzpGkVUzMfI_yoIzwpaJh41zd77nO_xe49e0FQNEEIjh__C4svctz7RA_90pteFDQ8TBoSmm8j6Jb-BdaDVIt_Ax77RRAiPD5ZSSqj-XzkjIUCNjghWjDz6H_k1FbcBA-lTBaia1tvioWh7A",
"dp": "vue3TBAlgr8Nkqk6XrMyC1E-IeggVKl-DnggFLCcXzShA1CcLavaLU95t6IwlkXs9AsiLgbkEpsfeSxZrnxcBDRbDYWl3b3hFuSfYAHgZFiW0L9_XkC0-xgvHePkKgcmn3fFHBKZBti2lcnKMHqhw_oFiZbfY4r60mma7TmAoQ0",
"alg": "PS256",
"dq": "O75nNblt8Fwg6OOM2VyDSqa-sgku1WTMuPKfBnUBH76C6olhuQdY1wwEVc1_asHgNla4yzOPTxKdazLdAPUHIOUrW7cfQJCCyLT-T03y2KxZEtfAd4mV0r-0Q3Addvn3qArr61K6ZNF3L74Wg2FozFDkl6g1jN3B00XMTi27xmU",
"n": "k7KVREAwJPKOfJC9Q71ZA3MZyZpv2S0wRDtz4wurqu2kNNd33-pIAkUABnSFDWxHdrXF0lL6fBJ558f5ybLk4rXE4dT0UJQLYxjBONoilkOIbZhXvtd-GWRy6bzmuRMBgUzvULTjCXSUpyllche6uStZFMRrlrRaZYGU1K0MNGmC6VzbKyYU8SJg9T9OupdtVSA0zmRtMeI7tk8-vQceonStkNrBklJ_pbqtFh-UpqRlZABJ-UqTNRY3Cm2x8X_QaEzGA-3eeRk4uNLTPVdgOOKven0lZdePRtdCowfXRxVwGrFGINonZn--gqlVc6rqo2KRIJgSTWXndIsb12G9aQ"
}
]
}
公钥
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "client-PS256",
"alg": "PS256",
"n": "k7KVREAwJPKOfJC9Q71ZA3MZyZpv2S0wRDtz4wurqu2kNNd33-pIAkUABnSFDWxHdrXF0lL6fBJ558f5ybLk4rXE4dT0UJQLYxjBONoilkOIbZhXvtd-GWRy6bzmuRMBgUzvULTjCXSUpyllche6uStZFMRrlrRaZYGU1K0MNGmC6VzbKyYU8SJg9T9OupdtVSA0zmRtMeI7tk8-vQceonStkNrBklJ_pbqtFh-UpqRlZABJ-UqTNRY3Cm2x8X_QaEzGA-3eeRk4uNLTPVdgOOKven0lZdePRtdCowfXRxVwGrFGINonZn--gqlVc6rqo2KRIJgSTWXndIsb12G9aQ"
}
]
}
claims
{
"aud": "http://localhost:8080/auth/realms/openbanking",
"claims": {
"id_token": {
"openbanking_intent_id": {
"essential": true,
"value": "64a7d936-c063-45a9-bc81-40e851bc5d30"
}
}
},
"client_id": "client-PS256",
"exp": 1581680397,
"iss": "client-PS256",
"nonce": "SqoQKopVco",
"redirect_uri": "http://localhost:8080/v3/hello",
"response_type": "code id_token",
"scope": "openid accounts",
"state": "0nidnhEdvX"
}
header
{
"kid": "client-PS256",
"typ": "JWT",
"alg": "PS256"
}
加密代码
public static void main(String[] args) throws Exception {
Provider bc = BouncyCastleProviderSingleton.getInstance();
Security.addProvider(bc);
String pdpAddress = "http://localhost:8080";
String realmName = "openbanking";
String clientId = "client-PS256";
String redirectClientId = "client-PS256";
String clienSecret = "9563616a-31d2-45ce-94a2-c0109963a134";
String client_alg = "PS256";
String kid = "client-PS256";
String openbankingIntentIdValue = "64a7d936-c063-45a9-bc81-40e851bc5d30";
String state = "0nidnhEdvX";
String nonce = "SqoQKopVco";
String uri = "http://localhost:8080/v3/hello";
OpenbankingIntentId openbankingIntentId = new OpenbankingIntentId();
openbankingIntentId.setValue(openbankingIntentIdValue);
openbankingIntentId.setEssential(true);
IdToken idToken = new IdToken();
idToken.setOpenbanking_intent_id(openbankingIntentId);
ClaimsModel claimsModel = new ClaimsModel();
claimsModel.setId_token(idToken);
Claims claims = new Claims();
StringBuffer bufferAud = new StringBuffer();
bufferAud.append(pdpAddress);
bufferAud.append("/auth/realms/");
bufferAud.append(realmName);
String aud = bufferAud.toString();
claims.setAud(aud);
claims.setScope("openid accounts");
claims.setClaims(claimsModel);
claims.setIss(clientId);
claims.setResponse_type("code id_token");
claims.setRedirect_uri(uri);
claims.setState(state);
claims.setNonce(nonce);
claims.setExp(new Long(new Date(new Date().getTime() + 5 * 60 * 1000).getTime()).intValue());
claims.setClient_id(clientId);
JSONObject json = JSONObject.fromObject(claims);
String requestObjectClaims = json.toString();
BufferedReader reader = new BufferedReader(new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ps256jwt.json"), "UTF-8"));
StringBuilder sb = new StringBuilder();
String s; // 依次循环,至到读的值为空
while ((s = reader.readLine()) != null) {
sb.append(s);
}
reader.close();
String jwks = sb.toString();
JWTClaimsSet claimSet = JWTClaimsSet.parse(requestObjectClaims);
JWKSet jwkSet = JWKSet.parse(jwks);
if (jwkSet.getKeys().size() == 1) {
// figure out which algorithm to use
JWK jwk = jwkSet.getKeys().iterator().next();
JWSSigner signer = null;
if (jwk.getKeyType().equals(KeyType.RSA)) {
signer = new RSASSASigner((RSAKey) jwk);
} else if (jwk.getKeyType().equals(KeyType.EC)) {
signer = new ECDSASigner((ECKey) jwk);
} else if (jwk.getKeyType().equals(KeyType.OCT)) {
signer = new MACSigner((OctetSequenceKey) jwk);
}
JWSHeader header = new JWSHeader(JWSAlgorithm.parse(client_alg), JOSEObjectType.JWT, null, null, null, null, null, null, null, null, kid, null, null);
SignedJWT requestObject = new SignedJWT(header, claimSet);
requestObject.sign(signer);
// logger.debug("**********claims" + claimSet.toString());
// logger.debug("**********header" + header.toString());
// logger.debug("**********requestObject" + requestObject.serialize());
// logger.debug("**********key" + jwk.toJSONString());
StringBuffer buffer = new StringBuffer();
buffer.append(pdpAddress);
buffer.append("/auth/realms/");
buffer.append(realmName);
buffer.append("/protocol/openid-connect/auth?request=");
buffer.append(requestObject.serialize());
buffer.append("&client_id=");
buffer.append(redirectClientId);
buffer.append("&redirect_uri=");
buffer.append(uri);
buffer.append("&scope=openid%20accounts&response_type=code%20id_token");
String path = buffer.toString();
// logger.debug("**********path" + path);
// resultMap.put("path", path);
System.out.println("path*****" + path);
}
}
生成授权跳转页面地址
http://localhost:8080/auth/realms/openbanking/protocol/openid-connect/auth?request=eyJraWQiOiJjbGllbnQtUFMyNTYiLCJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJhdWQiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4MFwvYXV0aFwvcmVhbG1zXC9vcGVuYmFua2luZyIsInNjb3BlIjoib3BlbmlkIGFjY291bnRzIiwiY2xhaW1zIjp7ImlkX3Rva2VuIjp7Im9wZW5iYW5raW5nX2ludGVudF9pZCI6eyJ2YWx1ZSI6IjY0YTdkOTM2LWMwNjMtNDVhOS1iYzgxLTQwZTg1MWJjNWQzMCIsImVzc2VudGlhbCI6dHJ1ZX19fSwiaXNzIjoiY2xpZW50LVBTMjU2IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUgaWRfdG9rZW4iLCJyZWRpcmVjdF91cmkiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4MFwvdjNcL2hlbGxvIiwic3RhdGUiOiIwbmlkbmhFZHZYIiwiZXhwIjoxNTgxOTIxMTk4LCJub25jZSI6IlNxb1FLb3BWY28iLCJjbGllbnRfaWQiOiJjbGllbnQtUFMyNTYifQ.TqSYiATjGMk_aHxMliYP5jzANnnCOlAjF8H5fG99g9AEPa3asWhAJJVleXoekf5T56PRYWBEqjcTqJDrTYmthTEoSIAgGd7zalztt1TuWa-0FND43VzdsC2CEsh9B7BbNraROVMY1AKBzrPeTeEdgasH-RBVj-f9dQkIhFrJWplmXEZSZ0ZyvvcelWZqklfeSWH_3OCVlmUkf5TxJLtoXpHYlWZOTe_exm-jeKK_jWzuNsBvcAAVnfDG15EgZH6M8buecXtlatnOzM-SKWxPzfxlfg4HX8e8IPkANDoemCpQCZfPvblzHfBOdl0fk5mY9LQpaz-iHgDDCEtlkAIpFA&client_id=client-PS256&redirect_uri=http://localhost:8080/v3/hello&scope=openid%20accounts&response_type=code%20id_token
{
http://localhost:8080/auth/realms/openbanking/login-actions/authenticate?session_code=2iFMm2p6Hk3ynNwaQqDF6MRnoAuMiUn8ltUltgXfCCA&execution=b5a519cd-ce00-48fe-a890-72e4bf7fd5a1&client_id=client-RS256&tab_id=r2S0SP5L16Q
}
http://localhost:8888/v3/hello#state=0nidnhEdvX&session_state=89e57637-5e0d-4f26-b9b2-05b64bdd183a&code=f0b38a8a-1273-4b34-8f21-bbe2e1edbcfd.89e57637-5e0d-4f26-b9b2-05b64bdd183a.840ce672-051a-4630-a4bd-9eff8573ce4d
&id_token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJpdmhsSndKdm8xWlNzX1BuTTE0Q1ZFSG5fTUJ3cE5UMkQwSTlFQkFkZEw4In0.eyJqdGkiOiI4NDJjYmNlZS03MGM5LTQ0MzgtOGJhNi1kODhkMzliYmM3YTAiLCJleHAiOjE1OTA3MjIyNTIsIm5iZiI6MCwiaWF0IjoxNTkwNzIxOTUyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvb3BlbmJhbmtpbmciLCJhdWQiOiJjbGllbnQtUlMyNTYiLCJzdWIiOiJmMTUzYmIwZS0wMDczLTQ1ZWMtODU5NC1mMzJjODQ4ZjhmYWIiLCJ0eXAiOiJJRCIsImF6cCI6ImNsaWVudC1SUzI1NiIsIm5vbmNlIjoiU3FvUUtvcFZjbyIsImF1dGhfdGltZSI6MTU5MDcyMTk1Miwic2Vzc2lvbl9zdGF0ZSI6Ijg5ZTU3NjM3LTVlMGQtNGYyNi1iOWIyLTA1YjY0YmRkMTgzYSIsImNfaGFzaCI6IlVmMHNkakVLRHhxSV9EeW4ydmV4RUEiLCJhY3IiOiIxIiwic19oYXNoIjoiZm9GbUZmUWZyTXhLWVpOTnc5SGRRQSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoib3BlbmJhbmtpbmcifQ.RyG8eCt4gCdbC1yTyi69Xl4y3397IWlCkjG0J2LdoSMaLjpi9RBMc9louH1moqfOZewJMhuF27E4DXFFbcT9fiXHLFIfRhWHDRJP5CPKVIyjBMrmF2GiPCsNyCX1cAuINc5WujTKL49xGe1FmhYdkxDxJgnVAqQXab89VXQbRk1sctc2nYGaw6q2I9pOQtivbpYrZfl2Ttegvvq4P3I2L_e3v5XskS4VMxtjAwFWngnHjOXYDLPPLmNY-mwmn-Bvl35BiP2yaq9WQKb0TiUOTnDlX_84HmxFtv6yeE65qUIIr7xcBVvF1P6JmAj2eeC4wNnkc0lN0N8Qm1MTlAOyuQ
curl --location --request POST 'http://localhost:8080/auth/realms/openbanking/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=f0b38a8a-1273-4b34-8f21-bbe2e1edbcfd.89e57637-5e0d-4f26-b9b2-05b64bdd183a.840ce672-051a-4630-a4bd-9eff8573ce4d' \
--data-urlencode 'redirect_uri=http://localhost:8888/v3/hello' \
--data-urlencode 'client_id=client-RS256' \
--data-urlencode 'client_secret=cd949e24-1c96-4ea4-9cb8-03f61aa6c601'
获取到的token id_token中携带的是授权信息
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJpdmhsSndKdm8xWlNzX1BuTTE0Q1ZFSG5fTUJ3cE5UMkQwSTlFQkFkZEw4In0.eyJqdGkiOiIxMmNhZDI0Yy1kMGUzLTQ3YzctOGQwNy0wMGU4ODAyOTg4NWUiLCJleHAiOjE1OTA3MjI3MTUsIm5iZiI6MCwiaWF0IjoxNTkwNzIyNDE1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvb3BlbmJhbmtpbmciLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiZjE1M2JiMGUtMDA3My00NWVjLTg1OTQtZjMyYzg0OGY4ZmFiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiY2xpZW50LVJTMjU2Iiwibm9uY2UiOiJTcW9RS29wVmNvMSIsImF1dGhfdGltZSI6MTU5MDcyMjM5Mywic2Vzc2lvbl9zdGF0ZSI6IjNjZTkzOTVhLWI3YjQtNGQ2Ni05NjRlLTQ4MzcxMzhmNTFiOCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo4ODg4Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoib3BlbmJhbmtpbmcifQ.IafBnpwO0nj6JfLx6QnE-bmMYIlhiSrdY7cVPkh1vk6QQbs1XnBVW8ItBmsNdBjZblycPEUQF9C7Ud3GHwOQroKJn99t-Ytsskvy7crQUBeo0GTpVtpvsM2MLvGgKRWUVH31VVL24z-M5POaBAkNiAsGqcgViQCBApIPUP5qFGoNxbyNZAftEiIX_gvygjqN91Telh5aUflsN8FYssKnbKUnNr4TGFs1avTIDYvXToNJDra99GjydgsLkoRU7kp0pjYX8H-VAxXc9jnqkJphfSzdFsYIkVjmxHhKAAD_3IXKM-83yipR5eq_2uSJq_w4ibExp-N0CyqC71pvt0pSEA",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2YmNkZmNkNy1kOTQ2LTRkNzUtYWQxMi1mZjE0ZGYxZTM4MGMifQ.eyJqdGkiOiI5NDUxOTFhOS0zYWEzLTRlYWQtYTcyYi03YWJhZWMxN2M3NWQiLCJleHAiOjE1OTA3MjQyMTUsIm5iZiI6MCwiaWF0IjoxNTkwNzIyNDE1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvb3BlbmJhbmtpbmciLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvb3BlbmJhbmtpbmciLCJzdWIiOiJmMTUzYmIwZS0wMDczLTQ1ZWMtODU5NC1mMzJjODQ4ZjhmYWIiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiY2xpZW50LVJTMjU2Iiwibm9uY2UiOiJTcW9RS29wVmNvMSIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjNjZTkzOTVhLWI3YjQtNGQ2Ni05NjRlLTQ4MzcxMzhmNTFiOCIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.sZFYkOf-KgHlaCbOAOofiIr_Dq5xcqLHgdPGmr9za-8",
"token_type": "bearer",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJpdmhsSndKdm8xWlNzX1BuTTE0Q1ZFSG5fTUJ3cE5UMkQwSTlFQkFkZEw4In0.eyJqdGkiOiJjNjZmMDE3Zi05OGU5LTQ5ZjMtOWJkNi1lNGY5OGRhOTE0MjEiLCJleHAiOjE1OTA3MjI3MTUsIm5iZiI6MCwiaWF0IjoxNTkwNzIyNDE1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvb3BlbmJhbmtpbmciLCJhdWQiOiJjbGllbnQtUlMyNTYiLCJzdWIiOiJmMTUzYmIwZS0wMDczLTQ1ZWMtODU5NC1mMzJjODQ4ZjhmYWIiLCJ0eXAiOiJJRCIsImF6cCI6ImNsaWVudC1SUzI1NiIsIm5vbmNlIjoiU3FvUUtvcFZjbzEiLCJhdXRoX3RpbWUiOjE1OTA3MjIzOTMsInNlc3Npb25fc3RhdGUiOiIzY2U5Mzk1YS1iN2I0LTRkNjYtOTY0ZS00ODM3MTM4ZjUxYjgiLCJhY3IiOiIxIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJvcGVuYmFua2luZyJ9.c6n_QfMIlTCoZLoWwxaIrlt4L7qBmS5x91bcU31okW2xMgQsDNP_GBLUEjtIthP8hwtXnOh1UZKxrKxrVae0nxdLFxrZ9-t6FHXBseNRK8-JwWxijdvzSBj6UrAnHeUxDPdWsYF6gLn3_KOCJq0bGkXTPzJ6p0n6gZP-3070vvkrkWmjcTCh3wCrcpEIpI8o5z8QlqHLTbFEg78lkLZKhY8oEQZbIkMKJM3Xkz4lrvRGu3tZIAU3RfyyAwsRXwojwiugeS7GLHrNdoalUiR9oyor3NQ3fUfAASp-opracFKijzjbWxng3xNgkwa9biCBmAMgtiTNFLEOKPKbp9oSVA",
"not-before-policy": 1590722346,
"session_state": "3ce9395a-b7b4-4d66-964e-4837138f51b8",
"scope": "openid profile email"
}
curl --location --request POST 'http://localhost:8080/auth/realms/openbanking/protocol/openid-connect/token/introspect' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=client-RS256' \
--data-urlencode 'client_secret=cd949e24-1c96-4ea4-9cb8-03f61aa6c601' \
--data-urlencode 'token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJpdmhsSndKdm8xWlNzX1BuTTE0Q1ZFSG5fTUJ3cE5UMkQwSTlFQkFkZEw4In0.eyJqdGkiOiI1MTdjNjQ4MS00ODNkLTRiM2EtODcxYy1jMWNkODQ0M2JkZDkiLCJleHAiOjE1OTA3MjM1NTUsIm5iZiI6MCwiaWF0IjoxNTkwNzIzMjU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvb3BlbmJhbmtpbmciLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiZjE1M2JiMGUtMDA3My00NWVjLTg1OTQtZjMyYzg0OGY4ZmFiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiY2xpZW50LVJTMjU2Iiwibm9uY2UiOiJTcW9RS29wVmNvMyIsImF1dGhfdGltZSI6MTU5MDcyMzIyNSwic2Vzc2lvbl9zdGF0ZSI6IjliODg4MDJiLWUxN2YtNDRiNC04NDdkLTU3ZDExOTQ0ZGU2OSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo4ODg4Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoib3BlbmJhbmtpbmcifQ.b8P3gH46pH4fQJgoo4oPyDikGrxljZy_txEiQhPjh7iOivv22HGuqALK4SEmu0SoxaZ7qv4yj-hks0Dbn-RjWUncoLacDHEAXutsLQcE2LDAgEBVKzscpz7Om1cPMUvufH9ruMquohv0n9E-jJ-CBDljynhY12bN_kBKdB_t04rN6ZhqdpxB--vgzPrveXVuW_xzoOwFBswaC7ZsRZSEe77pOIBoZrhEzE-0nQ8VUaUxalNlnXiWJY4xolciqddPZ7iz1Mc6XLi_Q0SoW4Ut5vFpcv8QQDJnfrJSz3GifvFZZeqmuwsmIeUWJ202qqMksW3c-Ka0Uf9jcK1iDtvRLg'
解析完成
{
"jti": "517c6481-483d-4b3a-871c-c1cd8443bdd9",
"exp": 1590723555,
"nbf": 0,
"iat": 1590723255,
"iss": "http://localhost:8080/auth/realms/openbanking",
"aud": "account",
"sub": "f153bb0e-0073-45ec-8594-f32c848f8fab",
"typ": "Bearer",
"azp": "client-RS256",
"nonce": "SqoQKopVco3",
"auth_time": 1590723225,
"session_state": "9b88802b-e17f-44b4-847d-57d11944de69",
"preferred_username": "openbanking",
"email_verified": false,
"acr": "1",
"allowed-origins": [
"http://localhost:8888"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid profile email",
"client_id": "client-RS256",
"username": "openbanking",
"active": true
}
{
"jti": "bc4a2dc8-9e8b-4314-8d42-31d7fa9ff3bf",
"exp": 1590724567,
"nbf": 0,
"iat": 1590724267,
"iss": "http://localhost:8080/auth/realms/openbanking",
"aud": "client-RS256",
"sub": "f153bb0e-0073-45ec-8594-f32c848f8fab",
"typ": "ID",
"azp": "client-RS256",
"nonce": "SqoQKopVco3",
"auth_time": 1590724220,
"session_state": "23a61c31-50b4-4ace-92f6-b81028f083c8",
"preferred_username": "openbanking",
"email_verified": false,
"acr": "1",
"client_id": "client-RS256",
"username": "openbanking",
"active": true
}