完成google id token校验
This commit is contained in:
parent
022f0ba4bd
commit
47df2cf3cd
@ -44,20 +44,19 @@ impl GoogleJwtProfile {
|
||||
}
|
||||
|
||||
impl From<Value> 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<Value> 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<HashMap<String, String>> {
|
||||
async fn fetch_and_parse_google_public_keys() -> SocialResult<HashMap<String, Value>> {
|
||||
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<GoogleJwtProfile> {
|
||||
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.validate_aud = false;
|
||||
|
||||
let decoded = decode::<Value>(id_token, &DecodingKey::from_rsa_pem(key.as_bytes())?, &validation)?;
|
||||
let decoded = decode::<Value>(
|
||||
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<GoogleJwtProfile> {
|
||||
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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user