修改token
This commit is contained in:
parent
22f7649bca
commit
837a296d21
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -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"
|
||||
|
@ -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))
|
||||
}
|
||||
|
3
app.toml
3
app.toml
@ -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
|
@ -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不能为空"))]
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 }
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -4,5 +4,4 @@ pub mod core;
|
||||
pub mod resp;
|
||||
pub mod middleware;
|
||||
pub mod token;
|
||||
pub mod cache;
|
||||
pub mod social;
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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" }
|
@ -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)
|
||||
})?;
|
||||
|
@ -1,2 +1,5 @@
|
||||
pub mod account;
|
||||
pub mod feedback;
|
||||
pub mod sys_account;
|
||||
|
||||
pub mod utils;
|
19
service/src/sys_account.rs
Normal file
19
service/src/sys_account.rs
Normal 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()))))
|
||||
}
|
24
service/src/utils/login_cache.rs
Normal file
24
service/src/utils/login_cache.rs
Normal 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
1
service/src/utils/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod login_cache;
|
Loading…
Reference in New Issue
Block a user