feat: use current token for go to app instead of refresh token

This commit is contained in:
Fu Zi Xiang 2023-11-09 10:31:24 +08:00
parent 680d6fe5b1
commit e2d6d1df02
No known key found for this signature in database
3 changed files with 36 additions and 53 deletions

View File

@ -8,6 +8,7 @@ use axum::{
}; };
use axum_extra::extract::CookieJar; use axum_extra::extract::CookieJar;
use gotrue::grant::{Grant, RefreshTokenGrant}; use gotrue::grant::{Grant, RefreshTokenGrant};
use gotrue_entity::dto::GotrueTokenResponse;
use jwt::{Claims, Header}; use jwt::{Claims, Header};
use redis::{aio::ConnectionManager, AsyncCommands, FromRedisValue, ToRedisArgs}; use redis::{aio::ConnectionManager, AsyncCommands, FromRedisValue, ToRedisArgs};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
@ -66,17 +67,12 @@ impl SessionStorage {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct UserSession { pub struct UserSession {
pub session_id: String, pub session_id: String,
pub access_token: String, pub token: GotrueTokenResponse,
pub refresh_token: String,
} }
impl UserSession { impl UserSession {
pub fn new(session_id: String, access_token: String, refresh_token: String) -> Self { pub fn new(session_id: String, token: GotrueTokenResponse) -> Self {
Self { Self { session_id, token }
session_id,
access_token,
refresh_token,
}
} }
} }
@ -103,9 +99,9 @@ impl FromRequestParts<AppState> for UserSession {
.await .await
.ok_or(SessionRejection::SessionNotFound)?; .ok_or(SessionRejection::SessionNotFound)?;
if has_expired(session.access_token.as_str()) { if has_expired(session.token.access_token.as_str()) {
// Get new pair of access token and refresh token // Get new pair of access token and refresh token
let refresh_token = session.refresh_token; let refresh_token = session.token.refresh_token;
let new_token = state let new_token = state
.gotrue_client .gotrue_client
.clone() .clone()
@ -113,8 +109,8 @@ impl FromRequestParts<AppState> for UserSession {
.await .await
.map_err(|err| SessionRejection::RefreshTokenError(err.to_string()))?; .map_err(|err| SessionRejection::RefreshTokenError(err.to_string()))?;
session.access_token = new_token.access_token; session.token.access_token = new_token.access_token;
session.refresh_token = new_token.refresh_token; session.token.refresh_token = new_token.refresh_token;
// Update session in redis // Update session in redis
let _ = state let _ = state

View File

@ -14,7 +14,6 @@ use axum::Form;
use axum::{extract::State, routing::post, Router}; use axum::{extract::State, routing::post, Router};
use axum_extra::extract::cookie::Cookie; use axum_extra::extract::cookie::Cookie;
use axum_extra::extract::CookieJar; use axum_extra::extract::CookieJar;
use gotrue::grant::{Grant, RefreshTokenGrant};
use gotrue::params::{AdminDeleteUserParams, AdminUserParams, GenerateLinkParams, MagicLinkParams}; use gotrue::params::{AdminDeleteUserParams, AdminUserParams, GenerateLinkParams, MagicLinkParams};
use gotrue_entity::dto::{UpdateGotrueUserParams, User}; use gotrue_entity::dto::{UpdateGotrueUserParams, User};
@ -43,27 +42,14 @@ pub fn router() -> Router<AppState> {
} }
// provide a link which when open in browser, opens the appflowy app // provide a link which when open in browser, opens the appflowy app
pub async fn open_app_handler( pub async fn open_app_handler(session: UserSession) -> Result<HeaderMap, WebApiError<'static>> {
State(state): State<AppState>,
session: UserSession,
) -> Result<HeaderMap, WebApiError<'static>> {
let access_token_resp = state
.gotrue_client
.token(&Grant::RefreshToken(RefreshTokenGrant {
refresh_token: session.refresh_token.to_owned(),
}))
.await?;
// appflowy-flutter:// -> scheme that opens the Appflowy app
// login-callback -> agreed upon convention that frontend recognizes
// The rest are params that are passed to the app needed for login
let app_sign_in_url = format!( let app_sign_in_url = format!(
"appflowy-flutter://login-callback#access_token={}&expires_at={}&expires_in={}&refresh_token={}&token_type={}", "appflowy-flutter://login-callback#access_token={}&expires_at={}&expires_in={}&refresh_token={}&token_type={}",
access_token_resp.access_token, session.token.access_token,
access_token_resp.expires_at, session.token.expires_at,
access_token_resp.expires_in, session.token.expires_in,
access_token_resp.refresh_token, session.token.refresh_token,
access_token_resp.token_type, session.token.token_type,
); );
Ok(htmx_redirect(&app_sign_in_url)) Ok(htmx_redirect(&app_sign_in_url))
} }
@ -78,7 +64,7 @@ pub async fn invite_handler(
state state
.gotrue_client .gotrue_client
.magic_link( .magic_link(
&session.access_token, &session.token.access_token,
&MagicLinkParams { &MagicLinkParams {
email: param.email, email: param.email,
..Default::default() ..Default::default()
@ -102,7 +88,7 @@ pub async fn change_password_handler(
let res = state let res = state
.gotrue_client .gotrue_client
.update_user( .update_user(
&session.access_token, &session.token.access_token,
&UpdateGotrueUserParams { &UpdateGotrueUserParams {
password: Some(param.new_password), password: Some(param.new_password),
..Default::default() ..Default::default()
@ -147,7 +133,7 @@ pub async fn admin_update_user_handler(
let res = state let res = state
.gotrue_client .gotrue_client
.admin_update_user( .admin_update_user(
&session.access_token, &session.token.access_token,
&user_uuid, &user_uuid,
&AdminUserParams { &AdminUserParams {
password: Some(param.password.to_owned()), password: Some(param.password.to_owned()),
@ -167,7 +153,7 @@ pub async fn post_user_generate_link_handler(
let res = state let res = state
.gotrue_client .gotrue_client
.admin_generate_link( .admin_generate_link(
&session.access_token, &session.token.access_token,
&GenerateLinkParams { &GenerateLinkParams {
email, email,
..Default::default() ..Default::default()
@ -185,7 +171,7 @@ pub async fn admin_delete_user_handler(
state state
.gotrue_client .gotrue_client
.admin_delete_user( .admin_delete_user(
&session.access_token, &session.token.access_token,
&user_uuid, &user_uuid,
&AdminDeleteUserParams { &AdminDeleteUserParams {
should_soft_delete: true, should_soft_delete: true,
@ -208,7 +194,7 @@ pub async fn admin_add_user_handler(
}; };
let user = state let user = state
.gotrue_client .gotrue_client
.admin_add_user(&session.access_token, &add_user_params) .admin_add_user(&session.token.access_token, &add_user_params)
.await?; .await?;
Ok(user.into()) Ok(user.into())
} }
@ -226,11 +212,7 @@ pub async fn login_refresh_handler(
.await?; .await?;
let new_session_id = uuid::Uuid::new_v4(); let new_session_id = uuid::Uuid::new_v4();
let new_session = session::UserSession::new( let new_session = session::UserSession::new(new_session_id.to_string(), token);
new_session_id.to_string(),
token.access_token.to_string(),
token.refresh_token.to_owned(),
);
state.session_store.put_user_session(&new_session).await?; state.session_store.put_user_session(&new_session).await?;
let mut cookie = Cookie::new("session_id", new_session_id.to_string()); let mut cookie = Cookie::new("session_id", new_session_id.to_string());
@ -257,11 +239,7 @@ pub async fn login_handler(
.await?; .await?;
let new_session_id = uuid::Uuid::new_v4(); let new_session_id = uuid::Uuid::new_v4();
let new_session = session::UserSession::new( let new_session = session::UserSession::new(new_session_id.to_string(), token);
new_session_id.to_string(),
token.access_token.to_string(),
token.refresh_token.to_owned(),
);
state.session_store.put_user_session(&new_session).await?; state.session_store.put_user_session(&new_session).await?;
Ok(( Ok((

View File

@ -57,7 +57,10 @@ pub async fn user_user_handler(
State(state): State<AppState>, State(state): State<AppState>,
session: UserSession, session: UserSession,
) -> Result<Html<String>, WebAppError> { ) -> Result<Html<String>, WebAppError> {
let user = state.gotrue_client.user_info(&session.access_token).await?; let user = state
.gotrue_client
.user_info(&session.token.access_token)
.await?;
render_template(templates::UserDetails { user: &user }) render_template(templates::UserDetails { user: &user })
} }
@ -73,7 +76,10 @@ pub async fn home_handler(
State(state): State<AppState>, State(state): State<AppState>,
session: UserSession, session: UserSession,
) -> Result<Html<String>, WebAppError> { ) -> Result<Html<String>, WebAppError> {
let user = state.gotrue_client.user_info(&session.access_token).await?; let user = state
.gotrue_client
.user_info(&session.token.access_token)
.await?;
render_template(templates::Home { render_template(templates::Home {
user: &user, user: &user,
is_admin: is_admin(&user), is_admin: is_admin(&user),
@ -84,7 +90,10 @@ pub async fn admin_home_handler(
State(state): State<AppState>, State(state): State<AppState>,
session: UserSession, session: UserSession,
) -> Result<Html<String>, WebAppError> { ) -> Result<Html<String>, WebAppError> {
let user = state.gotrue_client.user_info(&session.access_token).await?; let user = state
.gotrue_client
.user_info(&session.token.access_token)
.await?;
render_template(templates::AdminHome { user: &user }) render_template(templates::AdminHome { user: &user })
} }
@ -94,7 +103,7 @@ pub async fn admin_users_handler(
) -> Result<Html<String>, WebAppError> { ) -> Result<Html<String>, WebAppError> {
let users = state let users = state
.gotrue_client .gotrue_client
.admin_list_user(&session.access_token) .admin_list_user(&session.token.access_token)
.await .await
.map_or_else( .map_or_else(
|err| { |err| {
@ -117,7 +126,7 @@ pub async fn admin_user_details_handler(
) -> Result<Html<String>, WebAppError> { ) -> Result<Html<String>, WebAppError> {
let user = state let user = state
.gotrue_client .gotrue_client
.admin_user_details(&session.access_token, &user_id) .admin_user_details(&session.token.access_token, &user_id)
.await .await
.unwrap(); // TODO: handle error .unwrap(); // TODO: handle error