発行者の署名付き名刺の概念を「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の全体像は大体わかったんだが、コレジャナイ感が強い。