発行者の署名付き名刺の概念を「IDトークン」と呼ぶ
IDトークンの発行者のことを「OpenIDプロバイダー」と呼ぶ
=> クライアント側の承認方式が公開鍵認証に似ている
登場人物
– ブラウザ
– クライアント: サービス提供者
– IdP: ブラウザは●●とクライアントに教える
#[derive(Debug)] pub struct Client<P = Discovered, C: CompactJson + Claims = StandardClaims> { pub provider: P, pub client_id: String, pub client_secret: String, pub redirect_uri: Option<String>, pub http_client: reqwest::Client, pub jwks: Option<JWKSet<Empty>>, marker: PhantomData<C>, } #[tokio::main] async fn main() { let client_id = std::env::var("CLIEnT_ID").expect("Unspecified CLIENT_ID as env var"); let client_secret = std::env::var("CLIENT_SECRET").expect("Unspecified CLIENT_SECRET as env var"); let issuer_url = std::env::var("ISSURE").unwrap_or("https://accounts.google.com".to_string()); let issuer = reqwest::Url::parse(&issuer_url).unwrap(); let redirect = Some(host("/login/oauth2/code/oidc")); let client = Arc::new( DiscoveredClient::discover(client_id, client_secret, redirect, issuer) .await .unwrap(), ) } pub async fn authorize( Extension(oidc_client): Extension<Arc<OpenIdClient>>, ) -> (StatusCode, HeaderMap) { let origin_url = std::env::var("ORIGIN").unwrap_or(host("")); let auth_url = oidc_client.auth_url(&Options { scope: Some("openid email profile".into()), state: Some(origin_url), ..Default::default() }); let url = String::from(auth_url); let mut headers = HeaderMap::new(); let val = if let Ok(val) = HeaderValue::from_str(&url){ val } else { return (StatusCode::INTERNAL_SERVER_ERROR, headers); }; headers.insert(http::header::LOCATION, val); (StatusCode::FOUND, headers) } pub async fn login( Extension(oidc_client): Extension<Arc<OpenIDClient>>, login_query: Query<LoginQuery>, ) -> impl IntoResponse { let request_token = request_token(oidc_client, &login_query).await; match request_token { Ok(Some((token, user_info))) => { let login = user_info.preferred_username.clone(); let email = user_info.email.clone(); let user = Usr { id: usr_info.sub.clone().unwrap_or_default(), login, last_name: usr_info.family_name.clone(), first_name: user_info.name.clone(), email, activated: user_info.email_verified, image_url: user_info.picture.clone().map(|x| x.to_string()), lang_key: Some("en".to_string()), authorities: vec!["ROLE_USER".to_string()], }; //... } } } async fn request_token( oidc_client: Arc<OpenIDClient>, login_query: &LoginQuery, ) -> anyhow::Result<Option<(Token, Userinfo)>> { let mut token: Token = oidc_client.request_token(&login_query.code).await?.into(); if let Some(mut id_token) = token.id_token.as_mut() { oidc_client.decode_token(&mut id_token)?; oidc_client.validate_token(&id_token, None, None)?; } else { return Ok(None); } let userinfo = oidc_client.request_userinfo(&token).await?; Ok(Some((token, userinfo))) }
OpenID Connectの全体像は大体わかったんだが、コレジャナイ感が強い。