mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-04 05:59:48 +08:00 
			
		
		
		
	feat(auth): Create and use SinglePurposeOrLoginTokenAuth (#4830)
				
					
				
			Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		@ -18,4 +18,4 @@ pub const MIN_PASSWORD_LENGTH: usize = 8;
 | 
				
			|||||||
pub const REDIS_TOTP_PREFIX: &str = "TOTP_";
 | 
					pub const REDIS_TOTP_PREFIX: &str = "TOTP_";
 | 
				
			||||||
pub const REDIS_RECOVERY_CODE_PREFIX: &str = "RC_";
 | 
					pub const REDIS_RECOVERY_CODE_PREFIX: &str = "RC_";
 | 
				
			||||||
pub const REDIS_TOTP_SECRET_PREFIX: &str = "TOTP_SEC_";
 | 
					pub const REDIS_TOTP_SECRET_PREFIX: &str = "TOTP_SEC_";
 | 
				
			||||||
pub const REDIS_TOTP_SECRET_TTL_IN_SECS: i64 = 5 * 60; // 5 minutes
 | 
					pub const REDIS_TOTP_SECRET_TTL_IN_SECS: i64 = 15 * 60; // 15 minutes
 | 
				
			||||||
 | 
				
			|||||||
@ -1237,11 +1237,11 @@ pub async fn create_merchant_account(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub async fn list_merchants_for_user(
 | 
					pub async fn list_merchants_for_user(
 | 
				
			||||||
    state: SessionState,
 | 
					    state: SessionState,
 | 
				
			||||||
    user_from_token: Box<dyn auth::GetUserIdFromAuth>,
 | 
					    user_from_token: auth::UserIdFromAuth,
 | 
				
			||||||
) -> UserResponse<Vec<user_api::UserMerchantAccount>> {
 | 
					) -> UserResponse<Vec<user_api::UserMerchantAccount>> {
 | 
				
			||||||
    let user_roles = state
 | 
					    let user_roles = state
 | 
				
			||||||
        .store
 | 
					        .store
 | 
				
			||||||
        .list_user_roles_by_user_id(user_from_token.get_user_id().as_str())
 | 
					        .list_user_roles_by_user_id(user_from_token.user_id.as_str())
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .change_context(UserErrors::InternalServerError)?;
 | 
					        .change_context(UserErrors::InternalServerError)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1697,7 +1697,7 @@ pub async fn reset_totp(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub async fn verify_totp(
 | 
					pub async fn verify_totp(
 | 
				
			||||||
    state: SessionState,
 | 
					    state: SessionState,
 | 
				
			||||||
    user_token: auth::UserFromSinglePurposeToken,
 | 
					    user_token: auth::UserIdFromAuth,
 | 
				
			||||||
    req: user_api::VerifyTotpRequest,
 | 
					    req: user_api::VerifyTotpRequest,
 | 
				
			||||||
) -> UserResponse<user_api::TokenResponse> {
 | 
					) -> UserResponse<user_api::TokenResponse> {
 | 
				
			||||||
    let user_from_db: domain::UserFromStorage = state
 | 
					    let user_from_db: domain::UserFromStorage = state
 | 
				
			||||||
@ -1737,7 +1737,7 @@ pub async fn verify_totp(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub async fn update_totp(
 | 
					pub async fn update_totp(
 | 
				
			||||||
    state: SessionState,
 | 
					    state: SessionState,
 | 
				
			||||||
    user_token: auth::UserFromSinglePurposeToken,
 | 
					    user_token: auth::UserIdFromAuth,
 | 
				
			||||||
    req: user_api::VerifyTotpRequest,
 | 
					    req: user_api::VerifyTotpRequest,
 | 
				
			||||||
) -> UserResponse<()> {
 | 
					) -> UserResponse<()> {
 | 
				
			||||||
    let user_from_db: domain::UserFromStorage = state
 | 
					    let user_from_db: domain::UserFromStorage = state
 | 
				
			||||||
@ -1806,7 +1806,7 @@ pub async fn update_totp(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub async fn generate_recovery_codes(
 | 
					pub async fn generate_recovery_codes(
 | 
				
			||||||
    state: SessionState,
 | 
					    state: SessionState,
 | 
				
			||||||
    user_token: auth::UserFromSinglePurposeToken,
 | 
					    user_token: auth::UserIdFromAuth,
 | 
				
			||||||
) -> UserResponse<user_api::RecoveryCodes> {
 | 
					) -> UserResponse<user_api::RecoveryCodes> {
 | 
				
			||||||
    if !tfa_utils::check_totp_in_redis(&state, &user_token.user_id).await? {
 | 
					    if !tfa_utils::check_totp_in_redis(&state, &user_token.user_id).await? {
 | 
				
			||||||
        return Err(UserErrors::TotpRequired.into());
 | 
					        return Err(UserErrors::TotpRequired.into());
 | 
				
			||||||
@ -1838,7 +1838,7 @@ pub async fn generate_recovery_codes(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub async fn verify_recovery_code(
 | 
					pub async fn verify_recovery_code(
 | 
				
			||||||
    state: SessionState,
 | 
					    state: SessionState,
 | 
				
			||||||
    user_token: auth::UserFromSinglePurposeToken,
 | 
					    user_token: auth::UserIdFromAuth,
 | 
				
			||||||
    req: user_api::VerifyRecoveryCodeRequest,
 | 
					    req: user_api::VerifyRecoveryCodeRequest,
 | 
				
			||||||
) -> UserResponse<user_api::TokenResponse> {
 | 
					) -> UserResponse<user_api::TokenResponse> {
 | 
				
			||||||
    let user_from_db: domain::UserFromStorage = state
 | 
					    let user_from_db: domain::UserFromStorage = state
 | 
				
			||||||
 | 
				
			|||||||
@ -1316,7 +1316,7 @@ impl User {
 | 
				
			|||||||
            // The route is utilized to select an invitation from a list of merchants in an intermediate state
 | 
					            // The route is utilized to select an invitation from a list of merchants in an intermediate state
 | 
				
			||||||
            .service(
 | 
					            .service(
 | 
				
			||||||
                web::resource("/merchants_select/list")
 | 
					                web::resource("/merchants_select/list")
 | 
				
			||||||
                    .route(web::get().to(list_merchants_for_user_with_spt)),
 | 
					                    .route(web::get().to(list_merchants_for_user)),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
 | 
					            .service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
 | 
				
			||||||
            .service(web::resource("/update").route(web::post().to(update_user_account_details)))
 | 
					            .service(web::resource("/update").route(web::post().to(update_user_account_details)))
 | 
				
			||||||
 | 
				
			|||||||
@ -318,24 +318,7 @@ pub async fn list_merchants_for_user(state: web::Data<AppState>, req: HttpReques
 | 
				
			|||||||
        &req,
 | 
					        &req,
 | 
				
			||||||
        (),
 | 
					        (),
 | 
				
			||||||
        |state, user, _, _| user_core::list_merchants_for_user(state, user),
 | 
					        |state, user, _, _| user_core::list_merchants_for_user(state, user),
 | 
				
			||||||
        &auth::DashboardNoPermissionAuth,
 | 
					        &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::AcceptInvite),
 | 
				
			||||||
        api_locking::LockAction::NotApplicable,
 | 
					 | 
				
			||||||
    ))
 | 
					 | 
				
			||||||
    .await
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn list_merchants_for_user_with_spt(
 | 
					 | 
				
			||||||
    state: web::Data<AppState>,
 | 
					 | 
				
			||||||
    req: HttpRequest,
 | 
					 | 
				
			||||||
) -> HttpResponse {
 | 
					 | 
				
			||||||
    let flow = Flow::UserMerchantAccountList;
 | 
					 | 
				
			||||||
    Box::pin(api::server_wrap(
 | 
					 | 
				
			||||||
        flow,
 | 
					 | 
				
			||||||
        state,
 | 
					 | 
				
			||||||
        &req,
 | 
					 | 
				
			||||||
        (),
 | 
					 | 
				
			||||||
        |state, user, _, _| user_core::list_merchants_for_user(state, user),
 | 
					 | 
				
			||||||
        &auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite),
 | 
					 | 
				
			||||||
        api_locking::LockAction::NotApplicable,
 | 
					        api_locking::LockAction::NotApplicable,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
@ -674,7 +657,7 @@ pub async fn totp_verify(
 | 
				
			|||||||
        &req,
 | 
					        &req,
 | 
				
			||||||
        json_payload.into_inner(),
 | 
					        json_payload.into_inner(),
 | 
				
			||||||
        |state, user, req_body, _| user_core::verify_totp(state, user, req_body),
 | 
					        |state, user, req_body, _| user_core::verify_totp(state, user, req_body),
 | 
				
			||||||
        &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP),
 | 
					        &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP),
 | 
				
			||||||
        api_locking::LockAction::NotApplicable,
 | 
					        api_locking::LockAction::NotApplicable,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
@ -692,7 +675,7 @@ pub async fn verify_recovery_code(
 | 
				
			|||||||
        &req,
 | 
					        &req,
 | 
				
			||||||
        json_payload.into_inner(),
 | 
					        json_payload.into_inner(),
 | 
				
			||||||
        |state, user, req_body, _| user_core::verify_recovery_code(state, user, req_body),
 | 
					        |state, user, req_body, _| user_core::verify_recovery_code(state, user, req_body),
 | 
				
			||||||
        &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP),
 | 
					        &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP),
 | 
				
			||||||
        api_locking::LockAction::NotApplicable,
 | 
					        api_locking::LockAction::NotApplicable,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
@ -710,7 +693,7 @@ pub async fn totp_update(
 | 
				
			|||||||
        &req,
 | 
					        &req,
 | 
				
			||||||
        json_payload.into_inner(),
 | 
					        json_payload.into_inner(),
 | 
				
			||||||
        |state, user, req_body, _| user_core::update_totp(state, user, req_body),
 | 
					        |state, user, req_body, _| user_core::update_totp(state, user, req_body),
 | 
				
			||||||
        &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP),
 | 
					        &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP),
 | 
				
			||||||
        api_locking::LockAction::NotApplicable,
 | 
					        api_locking::LockAction::NotApplicable,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
@ -724,7 +707,7 @@ pub async fn generate_recovery_codes(state: web::Data<AppState>, req: HttpReques
 | 
				
			|||||||
        &req,
 | 
					        &req,
 | 
				
			||||||
        (),
 | 
					        (),
 | 
				
			||||||
        |state, user, _, _| user_core::generate_recovery_codes(state, user),
 | 
					        |state, user, _, _| user_core::generate_recovery_codes(state, user),
 | 
				
			||||||
        &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP),
 | 
					        &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP),
 | 
				
			||||||
        api_locking::LockAction::NotApplicable,
 | 
					        api_locking::LockAction::NotApplicable,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
 | 
				
			|||||||
@ -64,10 +64,15 @@ pub enum AuthenticationType {
 | 
				
			|||||||
    UserJwt {
 | 
					    UserJwt {
 | 
				
			||||||
        user_id: String,
 | 
					        user_id: String,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    SinglePurposeJWT {
 | 
					    SinglePurposeJwt {
 | 
				
			||||||
        user_id: String,
 | 
					        user_id: String,
 | 
				
			||||||
        purpose: TokenPurpose,
 | 
					        purpose: TokenPurpose,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    SinglePurposeOrLoginJwt {
 | 
				
			||||||
 | 
					        user_id: String,
 | 
				
			||||||
 | 
					        purpose: Option<TokenPurpose>,
 | 
				
			||||||
 | 
					        role_id: Option<String>,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    MerchantId {
 | 
					    MerchantId {
 | 
				
			||||||
        merchant_id: String,
 | 
					        merchant_id: String,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -107,7 +112,8 @@ impl AuthenticationType {
 | 
				
			|||||||
            | Self::WebhookAuth { merchant_id } => Some(merchant_id.as_ref()),
 | 
					            | Self::WebhookAuth { merchant_id } => Some(merchant_id.as_ref()),
 | 
				
			||||||
            Self::AdminApiKey
 | 
					            Self::AdminApiKey
 | 
				
			||||||
            | Self::UserJwt { .. }
 | 
					            | Self::UserJwt { .. }
 | 
				
			||||||
            | Self::SinglePurposeJWT { .. }
 | 
					            | Self::SinglePurposeJwt { .. }
 | 
				
			||||||
 | 
					            | Self::SinglePurposeOrLoginJwt { .. }
 | 
				
			||||||
            | Self::NoAuth => None,
 | 
					            | Self::NoAuth => None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -189,6 +195,19 @@ pub struct UserFromToken {
 | 
				
			|||||||
    pub org_id: String,
 | 
					    pub org_id: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct UserIdFromAuth {
 | 
				
			||||||
 | 
					    pub user_id: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "olap")]
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
 | 
					pub struct SinglePurposeOrLoginToken {
 | 
				
			||||||
 | 
					    pub user_id: String,
 | 
				
			||||||
 | 
					    pub role_id: Option<String>,
 | 
				
			||||||
 | 
					    pub purpose: Option<TokenPurpose>,
 | 
				
			||||||
 | 
					    pub exp: u64,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait AuthInfo {
 | 
					pub trait AuthInfo {
 | 
				
			||||||
    fn get_merchant_id(&self) -> Option<&str>;
 | 
					    fn get_merchant_id(&self) -> Option<&str>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -205,23 +224,6 @@ impl AuthInfo for AuthenticationData {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait GetUserIdFromAuth {
 | 
					 | 
				
			||||||
    fn get_user_id(&self) -> String;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl GetUserIdFromAuth for UserFromToken {
 | 
					 | 
				
			||||||
    fn get_user_id(&self) -> String {
 | 
					 | 
				
			||||||
        self.user_id.clone()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "olap")]
 | 
					 | 
				
			||||||
impl GetUserIdFromAuth for UserFromSinglePurposeToken {
 | 
					 | 
				
			||||||
    fn get_user_id(&self) -> String {
 | 
					 | 
				
			||||||
        self.user_id.clone()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
pub trait AuthenticateAndFetch<T, A>
 | 
					pub trait AuthenticateAndFetch<T, A>
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
@ -355,7 +357,7 @@ where
 | 
				
			|||||||
                user_id: payload.user_id.clone(),
 | 
					                user_id: payload.user_id.clone(),
 | 
				
			||||||
                origin: payload.origin.clone(),
 | 
					                origin: payload.origin.clone(),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            AuthenticationType::SinglePurposeJWT {
 | 
					            AuthenticationType::SinglePurposeJwt {
 | 
				
			||||||
                user_id: payload.user_id,
 | 
					                user_id: payload.user_id,
 | 
				
			||||||
                purpose: payload.purpose,
 | 
					                purpose: payload.purpose,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -363,9 +365,13 @@ where
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "olap")]
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct SinglePurposeOrLoginTokenAuth(pub TokenPurpose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "olap")]
 | 
					#[cfg(feature = "olap")]
 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
impl<A> AuthenticateAndFetch<Box<dyn GetUserIdFromAuth>, A> for SinglePurposeJWTAuth
 | 
					impl<A> AuthenticateAndFetch<UserIdFromAuth, A> for SinglePurposeOrLoginTokenAuth
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
    A: SessionStateInfo + Sync,
 | 
					    A: SessionStateInfo + Sync,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -373,26 +379,35 @@ where
 | 
				
			|||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        request_headers: &HeaderMap,
 | 
					        request_headers: &HeaderMap,
 | 
				
			||||||
        state: &A,
 | 
					        state: &A,
 | 
				
			||||||
    ) -> RouterResult<(Box<dyn GetUserIdFromAuth>, AuthenticationType)> {
 | 
					    ) -> RouterResult<(UserIdFromAuth, AuthenticationType)> {
 | 
				
			||||||
        let payload = parse_jwt_payload::<A, SinglePurposeToken>(request_headers, state).await?;
 | 
					        let payload =
 | 
				
			||||||
 | 
					            parse_jwt_payload::<A, SinglePurposeOrLoginToken>(request_headers, state).await?;
 | 
				
			||||||
        if payload.check_in_blacklist(state).await? {
 | 
					        if payload.check_in_blacklist(state).await? {
 | 
				
			||||||
            return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
 | 
					            return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.0 != payload.purpose {
 | 
					        let is_purpose_equal = payload
 | 
				
			||||||
            return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
 | 
					            .purpose
 | 
				
			||||||
        }
 | 
					            .as_ref()
 | 
				
			||||||
 | 
					            .is_some_and(|purpose| purpose == &self.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok((
 | 
					        let purpose_exists = payload.purpose.is_some();
 | 
				
			||||||
            Box::new(UserFromSinglePurposeToken {
 | 
					        let role_id_exists = payload.role_id.is_some();
 | 
				
			||||||
                user_id: payload.user_id.clone(),
 | 
					
 | 
				
			||||||
                origin: payload.origin.clone(),
 | 
					        if is_purpose_equal && !role_id_exists || role_id_exists && !purpose_exists {
 | 
				
			||||||
            }),
 | 
					            Ok((
 | 
				
			||||||
            AuthenticationType::SinglePurposeJWT {
 | 
					                UserIdFromAuth {
 | 
				
			||||||
                user_id: payload.user_id,
 | 
					                    user_id: payload.user_id.clone(),
 | 
				
			||||||
                purpose: payload.purpose,
 | 
					                },
 | 
				
			||||||
            },
 | 
					                AuthenticationType::SinglePurposeOrLoginJwt {
 | 
				
			||||||
        ))
 | 
					                    user_id: payload.user_id,
 | 
				
			||||||
 | 
					                    purpose: payload.purpose,
 | 
				
			||||||
 | 
					                    role_id: payload.role_id,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ))
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Err(errors::ApiErrorResponse::InvalidJwtToken.into())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -864,37 +879,6 @@ where
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "olap")]
 | 
					 | 
				
			||||||
#[async_trait]
 | 
					 | 
				
			||||||
impl<A> AuthenticateAndFetch<Box<dyn GetUserIdFromAuth>, A> for DashboardNoPermissionAuth
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    A: SessionStateInfo + Sync,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    async fn authenticate_and_fetch(
 | 
					 | 
				
			||||||
        &self,
 | 
					 | 
				
			||||||
        request_headers: &HeaderMap,
 | 
					 | 
				
			||||||
        state: &A,
 | 
					 | 
				
			||||||
    ) -> RouterResult<(Box<dyn GetUserIdFromAuth>, AuthenticationType)> {
 | 
					 | 
				
			||||||
        let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
 | 
					 | 
				
			||||||
        if payload.check_in_blacklist(state).await? {
 | 
					 | 
				
			||||||
            return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Ok((
 | 
					 | 
				
			||||||
            Box::new(UserFromToken {
 | 
					 | 
				
			||||||
                user_id: payload.user_id.clone(),
 | 
					 | 
				
			||||||
                merchant_id: payload.merchant_id.clone(),
 | 
					 | 
				
			||||||
                org_id: payload.org_id,
 | 
					 | 
				
			||||||
                role_id: payload.role_id,
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
            AuthenticationType::MerchantJwt {
 | 
					 | 
				
			||||||
                merchant_id: payload.merchant_id,
 | 
					 | 
				
			||||||
                user_id: Some(payload.user_id),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(feature = "olap")]
 | 
					#[cfg(feature = "olap")]
 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
impl<A> AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth
 | 
					impl<A> AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ use redis_interface::RedisConnectionPool;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use super::AuthToken;
 | 
					use super::AuthToken;
 | 
				
			||||||
#[cfg(feature = "olap")]
 | 
					#[cfg(feature = "olap")]
 | 
				
			||||||
use super::SinglePurposeToken;
 | 
					use super::{SinglePurposeOrLoginToken, SinglePurposeToken};
 | 
				
			||||||
#[cfg(feature = "email")]
 | 
					#[cfg(feature = "email")]
 | 
				
			||||||
use crate::consts::{EMAIL_TOKEN_BLACKLIST_PREFIX, EMAIL_TOKEN_TIME_IN_SECS};
 | 
					use crate::consts::{EMAIL_TOKEN_BLACKLIST_PREFIX, EMAIL_TOKEN_TIME_IN_SECS};
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
@ -166,3 +166,14 @@ impl BlackList for SinglePurposeToken {
 | 
				
			|||||||
        check_user_in_blacklist(state, &self.user_id, self.exp).await
 | 
					        check_user_in_blacklist(state, &self.user_id, self.exp).await
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "olap")]
 | 
				
			||||||
 | 
					#[async_trait::async_trait]
 | 
				
			||||||
 | 
					impl BlackList for SinglePurposeOrLoginToken {
 | 
				
			||||||
 | 
					    async fn check_in_blacklist<A>(&self, state: &A) -> RouterResult<bool>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        A: SessionStateInfo + Sync,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        check_user_in_blacklist(state, &self.user_id, self.exp).await
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user