修改token
This commit is contained in:
parent
22f7649bca
commit
837a296d21
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -308,9 +308,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.4.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
|
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
@ -565,9 +565,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "5.3.0"
|
version = "5.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24"
|
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"parking",
|
"parking",
|
||||||
@ -1067,7 +1067,6 @@ dependencies = [
|
|||||||
"http-body-util",
|
"http-body-util",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"moka",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1173,17 +1172,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moka"
|
name = "moka"
|
||||||
version = "0.12.6"
|
version = "0.12.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87bfd249f570638bfb0b4f9d258e6b8cddd2a5a7d0ed47e8bb8b176bfc0e7a17"
|
checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"crossbeam-epoch",
|
"crossbeam-epoch",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"event-listener 5.3.0",
|
"event-listener 5.3.1",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"quanta",
|
"quanta",
|
||||||
@ -1591,9 +1591,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-cpuid"
|
name = "raw-cpuid"
|
||||||
version = "11.0.1"
|
version = "11.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1"
|
checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
]
|
]
|
||||||
@ -1924,7 +1924,9 @@ dependencies = [
|
|||||||
"domain",
|
"domain",
|
||||||
"error-stack",
|
"error-stack",
|
||||||
"futures-executor",
|
"futures-executor",
|
||||||
|
"lazy_static",
|
||||||
"library",
|
"library",
|
||||||
|
"moka",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2657,9 +2659,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "triomphe"
|
name = "triomphe"
|
||||||
version = "0.1.11"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
|
checksum = "1b2cb4fbb9995eeb36ac86fadf24031ccd58f99d6b4b2d7b911db70bddb80d90"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
|
@ -9,7 +9,7 @@ pub async fn authenticate_google(
|
|||||||
) -> ResResult<ResOK<()>> {
|
) -> ResResult<ResOK<()>> {
|
||||||
req.validate()?;
|
req.validate()?;
|
||||||
|
|
||||||
service::account::authticate_google(req).await?;
|
service::account::authenticate_google(req).await?;
|
||||||
|
|
||||||
Ok(ResOK(None))
|
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 }
|
options = { min_conns = 10, max_conns = 20, conn_timeout = 30, idle_timeout = 300, max_lifetime = 60, sql_logging = true }
|
||||||
|
|
||||||
[jwt]
|
[jwt]
|
||||||
secret = "chuanyue"
|
token_secret = "chuanyue"
|
||||||
|
refresh_token_secret = "chuanyue"
|
||||||
expires = 1800
|
expires = 1800
|
||||||
refresh_expires = 3600
|
refresh_expires = 3600
|
@ -1,6 +1,14 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use validator::Validate;
|
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)]
|
#[derive(Debug, Validate, Deserialize, Serialize)]
|
||||||
pub struct AuthenticateGooleAccountReq {
|
pub struct AuthenticateGooleAccountReq {
|
||||||
#[validate(required(message = "用户ID Token不能为空"), length(min = 1, message = "用户ID Token不能为空"))]
|
#[validate(required(message = "用户ID Token不能为空"), length(min = 1, message = "用户ID Token不能为空"))]
|
||||||
|
@ -131,4 +131,26 @@ impl Account {
|
|||||||
self.avatar_url.clone().unwrap()
|
self.avatar_url.clone().unwrap()
|
||||||
).fetch_one(db_pool).await
|
).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 = { workspace = true }
|
||||||
http-body = { workspace = true }
|
http-body = { workspace = true }
|
||||||
http-body-util = { workspace = true }
|
http-body-util = { workspace = true }
|
||||||
moka = { workspace = true, features = ["future"] }
|
|
||||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros" ] }
|
tokio = { workspace = true, features = ["rt-multi-thread", "macros" ] }
|
||||||
futures-util = { workspace = true }
|
futures-util = { workspace = true }
|
||||||
jsonwebtoken = { 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)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Jwt {
|
pub struct Jwt {
|
||||||
pub secret: String,
|
pub token_secret: String,
|
||||||
|
pub refresh_token_secret: String,
|
||||||
pub expires: i64,
|
pub expires: i64,
|
||||||
pub refresh_expires: i64,
|
pub refresh_expires: i64,
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,4 @@ pub mod core;
|
|||||||
pub mod resp;
|
pub mod resp;
|
||||||
pub mod middleware;
|
pub mod middleware;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod cache;
|
|
||||||
pub mod social;
|
pub mod social;
|
@ -19,7 +19,7 @@ pub async fn authenticate_access_token(mut req: Request, next: Next) -> Response
|
|||||||
};
|
};
|
||||||
|
|
||||||
let validation = Validation::default();
|
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) => {
|
Ok(decoded) => {
|
||||||
// 将Claims附加到请求扩展中,以便后续处理使用
|
// 将Claims附加到请求扩展中,以便后续处理使用
|
||||||
req.extensions_mut().insert(decoded.claims);
|
req.extensions_mut().insert(decoded.claims);
|
||||||
|
@ -14,22 +14,10 @@ pub fn generate_token(sub: &str) -> String {
|
|||||||
sub: sub.to_string(),
|
sub: sub.to_string(),
|
||||||
exp: (Utc::now() + TimeDelta::try_seconds(config!().jwt.expires).unwrap()).timestamp(),
|
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(
|
let token = jsonwebtoken::encode(
|
||||||
&jsonwebtoken::Header::default(),
|
&jsonwebtoken::Header::default(),
|
||||||
&claim,
|
&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| {
|
token.unwrap_or_else(|e| {
|
||||||
tracing::error!(error =?e, "生成Token失败");
|
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> {
|
pub fn verify_token(token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
|
||||||
jsonwebtoken::decode::<Claims>(
|
jsonwebtoken::decode::<Claims>(
|
||||||
token,
|
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(),
|
&jsonwebtoken::Validation::default(),
|
||||||
)
|
)
|
||||||
.map(|data| data.claims)
|
.map(|data| data.claims)
|
||||||
|
@ -12,6 +12,8 @@ reqwest = { workspace = true }
|
|||||||
futures-executor = { workspace = true }
|
futures-executor = { workspace = true }
|
||||||
error-stack = { workspace = true }
|
error-stack = { workspace = true }
|
||||||
sqlx = { workspace = true, features = ["uuid"] }
|
sqlx = { workspace = true, features = ["uuid"] }
|
||||||
|
moka = { workspace = true, features = ["future", "logging"] }
|
||||||
|
lazy_static = { workspace = true }
|
||||||
|
|
||||||
library = { path = "../library" }
|
library = { path = "../library" }
|
||||||
domain = { path = "../domain" }
|
domain = { path = "../domain" }
|
@ -1,14 +1,13 @@
|
|||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use domain::dto::account::AuthenticateGooleAccountReq;
|
use domain::dto::account::AuthenticateGooleAccountReq;
|
||||||
use domain::entities::account::Account;
|
use domain::entities::account::Account;
|
||||||
use library::social::apple::APPLE_SOCIAL;
|
|
||||||
use library::{db, token};
|
use library::{db, token};
|
||||||
use library::resp::response::ResErr::ErrPerm;
|
use library::resp::response::ResErr::ErrPerm;
|
||||||
use library::resp::response::{ResErr, ResOK, ResResult};
|
use library::resp::response::{ResErr, ResOK, ResResult};
|
||||||
use library::social::google::GOOGLE_SOCIAL;
|
use library::social::google::GOOGLE_SOCIAL;
|
||||||
|
|
||||||
pub async fn authticate_google(req: AuthenticateGooleAccountReq) -> ResResult<ResOK<(String, String)>> {
|
pub async fn authenticate_google(req: AuthenticateGooleAccountReq) -> ResResult<ResOK<(String, String)>> {
|
||||||
let verify_result = APPLE_SOCIAL.verify_id_token(&req.id_token.unwrap()).await.map_err(|err| {
|
let verify_result = GOOGLE_SOCIAL.verify_id_token(&req.id_token.unwrap()).await.map_err(|err| {
|
||||||
tracing::error!(error = ?err, "校验Google Token失败");
|
tracing::error!(error = ?err, "校验Google Token失败");
|
||||||
ErrPerm(None)
|
ErrPerm(None)
|
||||||
})?;
|
})?;
|
||||||
|
@ -1,2 +1,5 @@
|
|||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod feedback;
|
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