添加firebase id token 校验

This commit is contained in:
李运家 2024-05-01 17:09:23 +08:00
parent ec6b061ed7
commit 4db49d4dc6
5 changed files with 84 additions and 4 deletions

27
Cargo.lock generated
View File

@ -171,7 +171,11 @@ dependencies = [
name = "auth"
version = "0.1.0"
dependencies = [
"error-stack",
"futures-executor",
"reqwest",
"rs-firebase-admin-sdk",
"tracing",
]
[[package]]
@ -2022,6 +2026,7 @@ dependencies = [
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.4.2",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
@ -2041,6 +2046,7 @@ dependencies = [
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
"tower-service",
@ -2910,6 +2916,27 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "tagptr"
version = "0.2.0"

View File

@ -7,3 +7,7 @@ edition = "2021"
[dependencies]
rs-firebase-admin-sdk = "2.0.0"
reqwest = "0.12.4"
futures-executor = "0.3.30"
error-stack = "0.4.1"
tracing = "0.1.40"

View File

@ -1,8 +1,44 @@
use std::sync::OnceLock;
use error_stack::Report;
use futures_executor::block_on;
use rs_firebase_admin_sdk::{
auth::{FirebaseAuthService, UserIdentifiers},
client::ApiHttpClient,
App, AuthenticationManager,
};
use rs_firebase_admin_sdk::auth::token::{LiveTokenVerifier, TokenVerifier};
use rs_firebase_admin_sdk::auth::token::cache::{HttpCache, PubKeys};
use rs_firebase_admin_sdk::auth::token::error::TokenVerificationError;
use rs_firebase_admin_sdk::auth::token::jwt::JWToken;
static LIVE_APP: OnceLock<App<AuthenticationManager>> = OnceLock::new();
static ID_TOKEN_VERIFIER: OnceLock<LiveTokenVerifier<HttpCache<reqwest::Client, PubKeys>>> = OnceLock::new();
fn get_app() -> &'static App<AuthenticationManager> {
LIVE_APP.get_or_init(|| block_on(async {
let gcp_service_account = AuthenticationManager::new().await.expect("Error while creating authentication manager");
App::live(gcp_service_account.into()).await.expect("Error while creating live app")
}))
}
fn get_id_token_verifier() -> &'static LiveTokenVerifier<HttpCache<reqwest::Client, PubKeys>> {
ID_TOKEN_VERIFIER.get_or_init(|| block_on(async {
get_app().id_token_verifier().await.expect("Error while creating id token verifier")
}))
}
pub async fn verify_user_id_token(id_token: &str) -> Result<JWToken, String> {
match get_id_token_verifier().verify_token(id_token).await {
Ok(jwtToken) => {
Ok(jwtToken)
}
Err(error) => {
tracing::error!("Error while verifying token: {:?}", error);
Err(error.to_string())
}
}
}
async fn test() {
// Load your GCP SA from env, see https://crates.io/crates/gcp_auth for more details
@ -10,6 +46,8 @@ async fn test() {
// Create live (not emulated) context for Firebase app
let live_app = App::live(gcp_service_account.into()).await.unwrap();
let id_token_verifier = live_app.id_token_verifier().await.expect("Error while creating id token verifier");
let verify_result = id_token_verifier.verify_token("").await.expect("Error while verifying token");
// Create Firebase authentication admin client
let auth_admin = live_app.auth();

View File

@ -5,12 +5,14 @@ use validator::Validate;
pub struct PlayerInfoRegister {
#[validate(required(message = "用户名称不能为空"), length(min = 1, message = "用户名称不能为空"))]
pub username: Option<String>,
#[validate(required, length(min = 1, message = "电子邮箱不能为空"))]
#[validate(required(message = "电子邮箱不能为空"), length(min = 1, message = "电子邮箱不能为空"))]
pub email: Option<String>,
#[validate(required, length(min = 1, message = "平台ID不能为空"))]
#[validate(required(message = "平台ID不能为空"), length(min = 1, message = "平台ID不能为空"))]
pub platform_id: Option<String>,
#[validate(required, length(min = 1, message = "用户类型不能为空"))]
#[validate(required(message = "用户类型不能为空"), length(min = 1, message = "用户类型不能为空"))]
pub user_type: Option<String>,
#[validate(required, length(min = 1, message = "用户所属区域不能为空"))]
#[validate(required(message = "用户所属区域不能为空"), length(min = 1, message = "用户所属区域不能为空"))]
pub country_code: Option<String>,
#[validate(required(message = "用户ID Token不能为空"), length(min = 1, message = "用户ID Token不能为空"))]
pub idToken: Option<String>
}

View File

@ -5,6 +5,7 @@ use library::db;
use library::resp::response::ResErr::{ErrPerm, ErrSystem};
use library::resp::response::{ResOK, ResResult};
use sea_orm::{ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set};
use auth::firebase_admin;
pub async fn register(req: PlayerInfoRegister) -> ResResult<ResOK<()>> {
match PlayerInfo::find()
@ -23,6 +24,14 @@ pub async fn register(req: PlayerInfoRegister) -> ResResult<ResOK<()>> {
}
}
let verified_token = match firebase_admin::verify_user_id_token(req.idToken.unwrap().as_str()).await {
Ok(token) => token,
Err(err) => {
tracing::error!(error = ?err, "err verify user id token");
return Err(ErrSystem(None));
}
};
let now = chrono::Local::now().naive_local();
let model = player_info::ActiveModel {