修改token

This commit is contained in:
李运家 2024-05-30 14:11:49 +08:00
parent 22f7649bca
commit 837a296d21
17 changed files with 128 additions and 52 deletions

26
Cargo.lock generated
View File

@ -308,9 +308,9 @@ dependencies = [
[[package]]
name = "concurrent-queue"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
]
@ -565,9 +565,9 @@ dependencies = [
[[package]]
name = "event-listener"
version = "5.3.0"
version = "5.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24"
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
dependencies = [
"concurrent-queue",
"parking",
@ -1067,7 +1067,6 @@ dependencies = [
"http-body-util",
"jsonwebtoken",
"lazy_static",
"moka",
"once_cell",
"reqwest",
"serde",
@ -1173,17 +1172,18 @@ dependencies = [
[[package]]
name = "moka"
version = "0.12.6"
version = "0.12.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87bfd249f570638bfb0b4f9d258e6b8cddd2a5a7d0ed47e8bb8b176bfc0e7a17"
checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08"
dependencies = [
"async-lock",
"async-trait",
"crossbeam-channel",
"crossbeam-epoch",
"crossbeam-utils",
"event-listener 5.3.0",
"event-listener 5.3.1",
"futures-util",
"log",
"once_cell",
"parking_lot",
"quanta",
@ -1591,9 +1591,9 @@ dependencies = [
[[package]]
name = "raw-cpuid"
version = "11.0.1"
version = "11.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1"
checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd"
dependencies = [
"bitflags 2.4.2",
]
@ -1924,7 +1924,9 @@ dependencies = [
"domain",
"error-stack",
"futures-executor",
"lazy_static",
"library",
"moka",
"reqwest",
"sqlx",
"tracing",
@ -2657,9 +2659,9 @@ dependencies = [
[[package]]
name = "triomphe"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
checksum = "1b2cb4fbb9995eeb36ac86fadf24031ccd58f99d6b4b2d7b911db70bddb80d90"
[[package]]
name = "try-lock"

View File

@ -9,7 +9,7 @@ pub async fn authenticate_google(
) -> ResResult<ResOK<()>> {
req.validate()?;
service::account::authticate_google(req).await?;
service::account::authenticate_google(req).await?;
Ok(ResOK(None))
}

View File

@ -13,6 +13,7 @@ url = "postgres://lyj:1325479Lyj!@47.95.198.7:13207/demo_rs"
options = { min_conns = 10, max_conns = 20, conn_timeout = 30, idle_timeout = 300, max_lifetime = 60, sql_logging = true }
[jwt]
secret = "chuanyue"
token_secret = "chuanyue"
refresh_token_secret = "chuanyue"
expires = 1800
refresh_expires = 3600

View File

@ -1,6 +1,14 @@
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Debug, Validate, Deserialize, Serialize)]
pub struct AuthenticateWithPassword {
#[validate(required(message = "用户名不能为空"), length(min = 1, message = "用户名不能为空"))]
pub username: Option<String>,
#[validate(required(message = "密码不能为空"), length(min = 1, message = "密码不能为空"))]
pub password: Option<String>,
}
#[derive(Debug, Validate, Deserialize, Serialize)]
pub struct AuthenticateGooleAccountReq {
#[validate(required(message = "用户ID Token不能为空"), length(min = 1, message = "用户ID Token不能为空"))]

View File

@ -131,4 +131,26 @@ impl Account {
self.avatar_url.clone().unwrap()
).fetch_one(db_pool).await
}
pub async fn find_with_password(username: String, password: String, db_pool: &PgPool) -> Result<Option<Account>, Error> {
match sqlx::query_as!(
Account,
r#"
select * from account where username = $1 and password = $2
"#,
username,
password.as_bytes()
).fetch_one(db_pool).await {
Ok(account) => {
return Ok(Some(account));
}
Err(Error::RowNotFound) => {
return Ok(None);
}
Err(e) => {
tracing::error!("find_by_google_id error: {:?}", e);
return Err(e);
}
}
}
}

View File

@ -21,7 +21,6 @@ serde_json = { workspace = true }
http = { workspace = true }
http-body = { workspace = true }
http-body-util = { workspace = true }
moka = { workspace = true, features = ["future"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros" ] }
futures-util = { workspace = true }
jsonwebtoken = { workspace = true }

View File

@ -1,17 +0,0 @@
use std::sync::OnceLock;
use moka::future::Cache;
#[macro_export]
macro_rules! auth_cache {
() => {
library::core::auth_cache::init_auth_cache()
};
}
static AUTH_CACHE: OnceLock<Cache<String, String>> = OnceLock::new();
pub fn init_auth_cache() -> &'static Cache<String, String> {
AUTH_CACHE.get_or_init(|| {
Cache::new(1000)
})
}

View File

@ -42,7 +42,8 @@ pub struct Logger {
#[derive(Clone, Debug, Deserialize)]
pub struct Jwt {
pub secret: String,
pub token_secret: String,
pub refresh_token_secret: String,
pub expires: i64,
pub refresh_expires: i64,
}

View File

@ -4,5 +4,4 @@ pub mod core;
pub mod resp;
pub mod middleware;
pub mod token;
pub mod cache;
pub mod social;

View File

@ -19,7 +19,7 @@ pub async fn authenticate_access_token(mut req: Request, next: Next) -> Response
};
let validation = Validation::default();
match decode::<Claims>(token, &DecodingKey::from_secret(config!().jwt.secret.as_bytes()), &validation) {
match decode::<Claims>(token, &DecodingKey::from_secret(config!().jwt.token_secret.as_bytes()), &validation) {
Ok(decoded) => {
// 将Claims附加到请求扩展中以便后续处理使用
req.extensions_mut().insert(decoded.claims);

View File

@ -14,22 +14,10 @@ pub fn generate_token(sub: &str) -> String {
sub: sub.to_string(),
exp: (Utc::now() + TimeDelta::try_seconds(config!().jwt.expires).unwrap()).timestamp(),
};
generate(claim)
}
pub fn generate_refresh_token(sub: &str) -> String {
let claim = Claims {
sub: sub.to_string(),
exp: (Utc::now() + TimeDelta::try_seconds(config!().jwt.refresh_expires).unwrap()).timestamp(),
};
generate(claim)
}
fn generate(claim: Claims) -> String {
let token = jsonwebtoken::encode(
&jsonwebtoken::Header::default(),
&claim,
&jsonwebtoken::EncodingKey::from_secret(config!().jwt.secret.as_bytes()),
&jsonwebtoken::EncodingKey::from_secret(config!().jwt.token_secret.as_bytes()),
);
token.unwrap_or_else(|e| {
tracing::error!(error =?e, "生成Token失败");
@ -37,10 +25,35 @@ fn generate(claim: Claims) -> String {
})
}
pub fn generate_refresh_token(sub: &str) -> String {
let claim = Claims {
sub: sub.to_string(),
exp: (Utc::now() + TimeDelta::try_seconds(config!().jwt.expires).unwrap()).timestamp(),
};
let token = jsonwebtoken::encode(
&jsonwebtoken::Header::default(),
&claim,
&jsonwebtoken::EncodingKey::from_secret(config!().jwt.refresh_token_secret.as_bytes()),
);
token.unwrap_or_else(|e| {
tracing::error!(error =?e, "生成Rfresh Token失败");
"".to_string()
})
}
pub fn verify_token(token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
jsonwebtoken::decode::<Claims>(
token,
&jsonwebtoken::DecodingKey::from_secret(config!().jwt.secret.as_bytes()),
&jsonwebtoken::DecodingKey::from_secret(config!().jwt.token_secret.as_bytes()),
&jsonwebtoken::Validation::default(),
)
.map(|data| data.claims)
}
pub fn verify_refresh_token(token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
jsonwebtoken::decode::<Claims>(
token,
&jsonwebtoken::DecodingKey::from_secret(config!().jwt.refresh_token_secret.as_bytes()),
&jsonwebtoken::Validation::default(),
)
.map(|data| data.claims)

View File

@ -12,6 +12,8 @@ reqwest = { workspace = true }
futures-executor = { workspace = true }
error-stack = { workspace = true }
sqlx = { workspace = true, features = ["uuid"] }
moka = { workspace = true, features = ["future", "logging"] }
lazy_static = { workspace = true }
library = { path = "../library" }
domain = { path = "../domain" }

View File

@ -1,14 +1,13 @@
use chrono::Utc;
use domain::dto::account::AuthenticateGooleAccountReq;
use domain::entities::account::Account;
use library::social::apple::APPLE_SOCIAL;
use library::{db, token};
use library::resp::response::ResErr::ErrPerm;
use library::resp::response::{ResErr, ResOK, ResResult};
use library::social::google::GOOGLE_SOCIAL;
pub async fn authticate_google(req: AuthenticateGooleAccountReq) -> ResResult<ResOK<(String, String)>> {
let verify_result = APPLE_SOCIAL.verify_id_token(&req.id_token.unwrap()).await.map_err(|err| {
pub async fn authenticate_google(req: AuthenticateGooleAccountReq) -> ResResult<ResOK<(String, String)>> {
let verify_result = GOOGLE_SOCIAL.verify_id_token(&req.id_token.unwrap()).await.map_err(|err| {
tracing::error!(error = ?err, "校验Google Token失败");
ErrPerm(None)
})?;

View File

@ -1,2 +1,5 @@
pub mod account;
pub mod feedback;
pub mod sys_account;
pub mod utils;

View File

@ -0,0 +1,19 @@
use chrono::Utc;
use domain::{dto::account::AuthenticateWithPassword, entities::account::Account};
use library::{db, resp::response::{ResErr, ResOK, ResResult}};
pub async fn authticate_with_password(req: AuthenticateWithPassword) -> ResResult<ResOK<(String, String)>> {
let account = Account::find_with_password(req.username.unwrap(), req.password.unwrap(), db!()).await?;
if account.is_none() {
tracing::info!("登录用户失败,用户查询为空");
return Err(ResErr::params("用户名或密码错误"));
}
let account = account.unwrap();
if account.disable_time > Utc::now() {
tracing::error!("账户已禁用");
return Err(ResErr::auth("账户已禁用"));
}
Ok(ResOK(Some(("".to_string(), "".to_string()))))
}

View File

@ -0,0 +1,24 @@
use std::time::Duration;
use lazy_static::lazy_static;
use library::config;
use moka::{
future::{Cache, CacheBuilder},
policy::EvictionPolicy,
};
#[derive(Debug, Clone)]
pub struct LoginAccount {}
lazy_static! {
pub static ref LOGIN_CACHE: Cache<String, LoginAccount> = {
CacheBuilder::new(20480)
.name("login_cache")
.eviction_policy(EvictionPolicy::lru())
.time_to_live(Duration::from_secs(config!().jwt.expires as u64))
.eviction_listener(|key, value, cause| {
tracing::info!("login_cache evict key: {:?}, value: {:?}, cause: {:?}", key, value, cause);
})
.build()
};
}

1
service/src/utils/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod login_cache;