From 47df2cf3cd7fd3729282eb278047cc95faa61b4f Mon Sep 17 00:00:00 2001 From: liyunjia Date: Wed, 29 May 2024 06:23:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90google=20id=20token=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/src/social/google.rs | 102 +++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/library/src/social/google.rs b/library/src/social/google.rs index 1bdab45..fe28887 100644 --- a/library/src/social/google.rs +++ b/library/src/social/google.rs @@ -37,27 +37,26 @@ pub struct GoogleJwtProfile { impl GoogleJwtProfile { fn new() -> Self { - GoogleJwtProfile{ + GoogleJwtProfile { ..Default::default() } } } impl From for GoogleJwtProfile { - fn from(value: Value) -> Self { let mut google_jwt_profile = GoogleJwtProfile::new(); if let Some(value) = value.get("iss") { - google_jwt_profile.iss = value.to_string(); + google_jwt_profile.iss = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("sub") { - google_jwt_profile.sub = value.to_string(); + google_jwt_profile.sub = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("azp") { - google_jwt_profile.azp = value.to_string(); + google_jwt_profile.azp = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("aud") { - google_jwt_profile.aud = value.to_string(); + google_jwt_profile.aud = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("iat") { google_jwt_profile.iat = value.as_i64().unwrap_or_default(); @@ -66,48 +65,82 @@ impl From for GoogleJwtProfile { google_jwt_profile.exp = value.as_i64().unwrap_or_default(); } if let Some(value) = value.get("email") { - google_jwt_profile.email = value.to_string(); + google_jwt_profile.email = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("email_verified") { google_jwt_profile.email_verified = value.as_bool().unwrap_or_default(); } if let Some(value) = value.get("at_hash") { - google_jwt_profile.at_hash = value.to_string(); + google_jwt_profile.at_hash = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("name") { - google_jwt_profile.name = value.to_string(); + google_jwt_profile.name = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("picture") { - google_jwt_profile.picture = value.to_string(); + google_jwt_profile.picture = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("given_name") { - google_jwt_profile.given_name = value.to_string(); + google_jwt_profile.given_name = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("family_name") { - google_jwt_profile.family_name = value.to_string(); + google_jwt_profile.family_name = value.as_str().unwrap().to_string(); } if let Some(value) = value.get("locale") { - google_jwt_profile.locale = value.to_string(); + google_jwt_profile.locale = value.as_str().unwrap().to_string(); } google_jwt_profile } - } // 异步获取并解析Google公钥 -async fn fetch_and_parse_google_public_keys() -> SocialResult> { +async fn fetch_and_parse_google_public_keys() -> SocialResult> { let response = Client::new().get(GOOGLE_PUBLIC_CERT_URL).send().await?; let google_keys: Value = response.json().await?; - let mut key_map = HashMap::new(); - if let Value::Object(keys_obj) = google_keys { - for (kid, key_val) in keys_obj { - if let Value::String(key) = key_val { - key_map.insert(kid, key); - } + /* Google公钥结构如下: + { + "keys": [ + { + "e": "AQAB", + "n": "xjWd1j8GmmWzuz732haG9HECXsSZBvxOBLph3FQhk_tplhWloI1ywx-RdopUZt1lndbOM9n99lZJkpQyNJ1sdy7JFgYLjqj-wtHdEaQlBGEQtmkW8zUjr_N3bmpsxGbPzOzlKe3qddtoxXvn9rI_RvHfJD1YY-6kayQeyPOBz_4ML1lvI_JHV-Bb1MSmSk3WaAh5PzeqleusmUT87Gqfu02cOPrY8cwugqo65D6-wzAEeVvceV8-c36TMoLU5csU05GBVplgd6Ouuw35ZsETG4si4QQJztC3KsZ4jhYM-aJ3jeFPt0r3cQooiXdZBp3JkXSpE-UUaOVPsXo7WiVmww", + "kty": "RSA", + "use": "sig", + "alg": "RS256", + "kid": "323b214ae6975a0f034ea77354dc0c25d03642dc" + }, + { + "kid": "6719678351a5faedc2e70274bbea62da2a8c4a12", + "n": "oAP5OnSzKfkEV2QMm2XCuu4G8VGRBOyhKg-4H04WzYzPqM_Tmqi60Vod96JTo7SfM0OoGeNnlkWNjjBWkSS66alNLrvTNLi0A-KGeBsZiIFmrbsP6HHJfFzPd0Mci7-e11fNKecZgbC1me9PtRXFZb9JprZGFOvBiMwU0rRvh0GWYmTFj1HFjOIMAwTGOKOVGNuPjv0b3V0YaAkUNklzi4MM6qgzUb0tE0so1Ii7kBe7roMScS2USPeeJkeoPjLEbQcrT8MxOSxH-JgPLfq-zOnEJ6ERW3mtXdZCNzqmVLn5yjX5lKr5E2vgkPAHx9NLZ09fo_L9woeX_5epl6cIkQ", + "use": "sig", + "alg": "RS256", + "kty": "RSA", + "e": "AQAB" } + ] } + */ + tracing::info!("Google公钥获取成功, {}", google_keys); + let mut key_map = HashMap::new(); + // 解析公钥 + google_keys + .get("keys") + .and_then(serde_json::Value::as_array) + .unwrap() + .iter() + .for_each(|key| { + if key + .get("kty") + .map(|kty| kty.as_str() == Some("RSA")) + .unwrap() + { + let n = key.get("n").unwrap().as_str().unwrap(); + let kid = key.get("kid").unwrap().as_str().unwrap(); + key_map.insert(kid.to_string(), key.clone()); + } + }); + + tracing::info!("Google公钥解析成功, {:?}", key_map); Ok(key_map) } @@ -127,13 +160,24 @@ pub async fn verify_id_token(id_token: &str) -> SocialResult { let kid = kid.unwrap(); // 根据kid找到正确的公钥 - let key = public_keys.get(&kid).ok_or_else(|| Box::new(ResErr::social("校验Token失败,未找到正确的公钥")))?; + let key = public_keys + .get(&kid) + .ok_or_else(|| Box::new(ResErr::social("校验Token失败,未找到正确的公钥")))?; + + tracing::info!("public key : {:?}", key); + let n = key.get("n").unwrap().as_str().unwrap(); + let e = &key.get("e").unwrap().as_str().unwrap(); // 验证Token let mut validation: Validation = Validation::new(Algorithm::RS256); - validation.set_issuer(&["https://accounts.google.com", "accounts.google.com"]);// 设置预期的发行者 + validation.set_issuer(&["https://accounts.google.com", "accounts.google.com"]); // 设置预期的发行者 + validation.validate_aud = false; - let decoded = decode::(id_token, &DecodingKey::from_rsa_pem(key.as_bytes())?, &validation)?; + let decoded = decode::( + id_token, + &DecodingKey::from_rsa_components(n, e).unwrap(), + &validation, + )?; let claims: Value = decoded.claims; let google_jwt_profile = GoogleJwtProfile::from(claims); @@ -142,16 +186,6 @@ pub async fn verify_id_token(id_token: &str) -> SocialResult { if google_jwt_profile.exp < Utc::now().timestamp() { return Err(Box::new(ResErr::social("校验Token失败,token有效期无效"))); } - // 校验签发时间 - // if google_jwt_profile.iat > Utc::now().timestamp() { - // return Err(Box::new(Error::from(ErrorKind::InvalidToken))); - // } - // if google_jwt_profile.aud != config::GOOGLE_CLIENT_ID { - // } - // 校验iss字段 - if google_jwt_profile.iss != "accounts.google.com" && google_jwt_profile.iss != "https://accounts.google.com" { - return Err(Box::new(ResErr::social("校验Token失败,token签发人非法"))); - } Ok(google_jwt_profile) }