chore: redirect url (#134)
* chore: redirect url * chore: stop ws conn if error is auth error * chore: add query params * chore: fix clippy
This commit is contained in:
parent
7c503372e0
commit
49f994488a
|
|
@ -59,6 +59,9 @@ pub struct Client {
|
|||
token: Arc<RwLock<ClientToken>>,
|
||||
}
|
||||
|
||||
/// Hardcoded schema in the frontend application. Do not change this value.
|
||||
const DESKTOP_CALLBACK_URL: &str = "appflowy-flutter://login-callback";
|
||||
|
||||
impl Client {
|
||||
/// Constructs a new `Client` instance.
|
||||
///
|
||||
|
|
@ -165,7 +168,9 @@ impl Client {
|
|||
///
|
||||
/// For example, the OAuth URL on Google looks like `https://appflowy.io/authorize?provider=google`.
|
||||
/// The deep link looks like `appflowy-flutter://#access_token=...&expires_in=3600&provider_token=...&refresh_token=...&token_type=bearer`.
|
||||
|
||||
///
|
||||
/// The appflowy-flutter:// is a hardcoded schema in the frontend application
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `provider`: A reference to an `OAuthProvider` indicating which OAuth provider to use for login.
|
||||
///
|
||||
|
|
@ -183,11 +188,30 @@ impl Client {
|
|||
return Err(ErrorCode::InvalidOAuthProvider.into());
|
||||
}
|
||||
|
||||
Ok(format!(
|
||||
"{}/authorize?provider={}&redirect_to=appflowy-flutter://",
|
||||
self.gotrue_client.base_url,
|
||||
provider.as_str(),
|
||||
))
|
||||
let url = format!("{}/authorize", self.gotrue_client.base_url,);
|
||||
|
||||
let mut url = Url::parse(&url)?;
|
||||
url
|
||||
.query_pairs_mut()
|
||||
.append_pair("provider", provider.as_str())
|
||||
.append_pair("redirect_to", DESKTOP_CALLBACK_URL);
|
||||
|
||||
if let OAuthProvider::Google = provider {
|
||||
url
|
||||
.query_pairs_mut()
|
||||
// In many cases, especially for server-side applications or mobile apps that might need to
|
||||
// interact with Google services on behalf of the user without the user being actively
|
||||
// engaged, access_type=offline is preferred to ensure long-term access.
|
||||
.append_pair("access_type", "offline")
|
||||
// In Google OAuth2.0, the prompt parameter is used to control the OAuth2.0 flow's behavior.
|
||||
// It determines if the user is re-prompted for authentication and/or consent.
|
||||
// 1. none: The authorization server does not display any authentication or consent user interface pages.
|
||||
// 2. consent: The authorization server prompts the user for consent before returning information to the client
|
||||
// 3. select_account: The authorization server prompts the user to select a user account.
|
||||
.append_pair("prompt", "consent");
|
||||
}
|
||||
|
||||
Ok(url.to_string())
|
||||
}
|
||||
|
||||
/// Returns an OAuth URL by constructing the authorization URL for the specified provider.
|
||||
|
|
@ -500,7 +524,7 @@ impl Client {
|
|||
.token
|
||||
.read()
|
||||
.as_ref()
|
||||
.ok_or::<AppError>(ErrorCode::NotLoggedIn.into())?
|
||||
.ok_or(AppError::new(ErrorCode::NotLoggedIn, "No access token"))?
|
||||
.refresh_token
|
||||
.as_str()
|
||||
.to_owned();
|
||||
|
|
|
|||
|
|
@ -244,7 +244,12 @@ struct RetryCondition {
|
|||
addr: Weak<parking_lot::Mutex<Option<String>>>,
|
||||
}
|
||||
impl Condition<WSError> for RetryCondition {
|
||||
fn should_retry(&mut self, _error: &WSError) -> bool {
|
||||
fn should_retry(&mut self, error: &WSError) -> bool {
|
||||
if let WSError::AuthError(err) = error {
|
||||
debug!("WSClient auth error: {}, stop retry connn", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
let should_retry = self
|
||||
.addr
|
||||
.upgrade()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
use crate::ws::ClientRealtimeMessage;
|
||||
use reqwest::StatusCode;
|
||||
use tokio_tungstenite::tungstenite::Error;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum WSError {
|
||||
#[error(transparent)]
|
||||
Tungstenite(#[from] tokio_tungstenite::tungstenite::error::Error),
|
||||
|
||||
#[error("Unsupported ws message type")]
|
||||
UnsupportedMsgType,
|
||||
|
||||
#[error(transparent)]
|
||||
TungsteniteError(Error),
|
||||
|
||||
#[error("Auth error: {0}")]
|
||||
AuthError(String),
|
||||
|
||||
#[error(transparent)]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
|
||||
|
|
@ -17,3 +22,14 @@ pub enum WSError {
|
|||
#[error("Internal failure: {0}")]
|
||||
Internal(#[from] Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
impl From<Error> for WSError {
|
||||
fn from(value: Error) -> Self {
|
||||
if let Error::Http(resp) = &value {
|
||||
if resp.status() == StatusCode::UNAUTHORIZED {
|
||||
return WSError::AuthError("Unauthorized ws connection".to_string());
|
||||
}
|
||||
}
|
||||
WSError::TungsteniteError(value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ impl actix_web::error::ResponseError for AppError {
|
|||
actix_web::HttpResponse::Ok().json(self)
|
||||
}
|
||||
}
|
||||
//
|
||||
impl From<anyhow::Error> for AppError {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
match err.downcast::<AppError>() {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use crate::component::auth::jwt::{authorization_from_token, UserUuid};
|
|||
use database::user::select_uid_from_uuid;
|
||||
use shared_entity::app_error::AppError;
|
||||
use std::time::Duration;
|
||||
use tracing::instrument;
|
||||
|
||||
pub fn ws_scope() -> Scope {
|
||||
web::scope("/ws").service(establish_ws_connection)
|
||||
|
|
@ -24,6 +25,8 @@ const MAX_FRAME_SIZE: usize = 65_536; // 64 KiB
|
|||
type CollabServerData = Data<
|
||||
Addr<CollabServer<CollabPostgresDBStorage, Arc<RealtimeUserImpl>, Arc<CollabAccessControlImpl>>>,
|
||||
>;
|
||||
|
||||
#[instrument(skip_all, err)]
|
||||
#[get("/{token}/{device_id}")]
|
||||
pub async fn establish_ws_connection(
|
||||
request: HttpRequest,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use sqlx::types::{uuid, Uuid};
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
|
|
@ -126,6 +127,7 @@ fn get_auth_from_request(req: &HttpRequest) -> Result<Authorization, actix_web::
|
|||
authorization_from_token(token, state)
|
||||
}
|
||||
|
||||
#[instrument(skip_all, err)]
|
||||
pub fn authorization_from_token(
|
||||
token: &str,
|
||||
state: &Data<AppState>,
|
||||
|
|
@ -137,6 +139,7 @@ pub fn authorization_from_token(
|
|||
})
|
||||
}
|
||||
|
||||
#[instrument(skip_all, err)]
|
||||
fn gotrue_jwt_claims_from_token(
|
||||
token: &str,
|
||||
state: &Data<AppState>,
|
||||
|
|
|
|||
Loading…
Reference in New Issue