Skip to content

Commit a764d3a

Browse files
committed
✨ 初步实现了账密登录能力。
1 parent 5e93a3d commit a764d3a

File tree

7 files changed

+78
-18
lines changed

7 files changed

+78
-18
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,6 @@ redis = { version = "^0.32", features = [
9494
"ahash",
9595
"uuid",
9696
"json",
97+
"aio",
9798
] }
9899
minio = "^0.3"

packages/functions/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ tracing-appender = { workspace = true }
4444
tracing-subscriber = { workspace = true }
4545

4646
sea-orm = { workspace = true }
47+
redis = { workspace = true }
48+
minio = { workspace = true }

packages/functions/src/functions/system/oauth.rs

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,76 @@
1-
use anyhow::Result;
1+
use anyhow::{anyhow, Result};
22

3+
use redis::{AsyncTypedCommands, SetOptions};
34
use sea_orm::prelude::*;
45

56
use _database::{models, DB_CONN};
6-
use _utils::types::auth::{OauthAnonymousResponse, OauthLoginResponse};
7+
use _utils::{
8+
bcrypt::verify_hash,
9+
jwt::{generate_token, EXPIRED_APPEND_DURATION},
10+
types::auth::{OauthAnonymousResponse, OauthLoginResponse, OauthScopeType, OauthTokenType},
11+
};
712

813
pub async fn oauth_password_login(
914
username: String,
1015
password: String,
1116
) -> Result<OauthLoginResponse> {
12-
let user = models::system::sys_user::Entity::find()
17+
let item = models::system::sys_user::Entity::find()
18+
.filter(models::system::sys_user::Column::DelFlag.eq(false))
1319
.filter(models::system::sys_user::Column::Username.eq(username))
1420
.one(&DB_CONN.wait().pg_conn)
15-
.await?;
21+
.await?
22+
.ok_or(anyhow!("User not found"))?;
1623

17-
// Continue with the login logic
24+
if !verify_hash(
25+
password,
26+
item.password
27+
.strip_prefix("{bcrypt}")
28+
.ok_or(anyhow!("Failed to strip bcrypt prefix"))?,
29+
)? {
30+
return Err(anyhow!("Invalid password"));
31+
}
1832

19-
todo!()
33+
let jti = Uuid::now_v7();
34+
let now = chrono::Utc::now();
35+
let access_token = generate_token(now, item.id, jti).await?;
36+
let refresh_token = generate_token(now, item.id, jti).await?;
37+
38+
let mut redis_conn = DB_CONN
39+
.wait()
40+
.redis_conn
41+
.get_multiplexed_async_connection()
42+
.await?;
43+
redis_conn
44+
.set_options(
45+
format!("jwt:access:{}:{}", item.id, jti),
46+
&access_token,
47+
SetOptions::default()
48+
.conditional_set(redis::ExistenceCheck::NX)
49+
.with_expiration(redis::SetExpiry::EX(
50+
EXPIRED_APPEND_DURATION.as_seconds_f32() as u64,
51+
)),
52+
)
53+
.await?;
54+
redis_conn
55+
.set_options(
56+
format!("jwt:refresh:{}:{}", item.id, jti),
57+
&refresh_token,
58+
SetOptions::default()
59+
.conditional_set(redis::ExistenceCheck::NX)
60+
.with_expiration(redis::SetExpiry::EX(
61+
EXPIRED_APPEND_DURATION.as_seconds_f32() as u64,
62+
)),
63+
)
64+
.await?;
65+
66+
Ok(OauthLoginResponse {
67+
access_token,
68+
refresh_token,
69+
token_type: OauthTokenType::Bearer,
70+
expires_in: EXPIRED_APPEND_DURATION.as_seconds_f32() as u64,
71+
scope: OauthScopeType::All,
72+
jti,
73+
})
2074
}
2175

2276
pub async fn oauth_client_credentials(scope: String) -> Result<OauthAnonymousResponse> {

packages/router/src/middlewares/auth_extrator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ where
3737

3838
return Ok(Self(Some(AuthInfo {
3939
token,
40-
user_id: claims.user_id,
40+
user_id: claims.sub,
4141
created_at: claims.iat,
4242
expires_at: claims.exp,
4343
})));

packages/utils/src/jwt.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use anyhow::{Context, Result};
22
use chrono::{DateTime, Utc};
33
use once_cell::sync::Lazy;
44
use serde::{Deserialize, Serialize};
5+
use uuid::Uuid;
56

67
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
78

@@ -47,25 +48,25 @@ mod jwt_numeric_date {
4748

4849
#[derive(Debug, PartialEq, Serialize, Deserialize)]
4950
pub struct Claims {
50-
pub user_id: i64,
51+
pub sub: i64,
52+
pub jti: Uuid,
5153
#[serde(with = "jwt_numeric_date")]
5254
pub iat: DateTime<Utc>,
5355
#[serde(with = "jwt_numeric_date")]
5456
pub exp: DateTime<Utc>,
5557
}
5658

57-
pub async fn generate_token(user_id: i64) -> Result<(String, DateTime<Utc>)> {
58-
let now = chrono::Utc::now();
59+
pub static EXPIRED_APPEND_DURATION: chrono::Duration = chrono::Duration::days(15);
60+
61+
pub async fn generate_token(now: DateTime<Utc>, user_id: i64, jti: Uuid) -> Result<String> {
5962
let claims = Claims {
60-
user_id,
63+
sub: user_id,
64+
jti,
6165
iat: now,
62-
exp: now + chrono::Duration::days(15),
66+
exp: now + EXPIRED_APPEND_DURATION,
6367
};
6468

65-
Ok((
66-
encode(&Header::default(), &claims, &JWT_SECRET.0).context("Failed to encode token")?,
67-
now,
68-
))
69+
Ok(encode(&Header::default(), &claims, &JWT_SECRET.0).context("Failed to encode token")?)
6970
}
7071

7172
pub async fn verify_token(token: &str) -> Result<Claims> {

packages/utils/src/types/auth.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub struct OauthAnonymousResponse {
3636
Debug, Clone, Copy, PartialEq, Default, EnumIter, Display, AsRefStr, Serialize, Deserialize,
3737
)]
3838
#[strum(serialize_all = "snake_case")]
39-
#[serde(rename_all = "snake_case", untagged)]
39+
#[serde(rename_all = "snake_case")]
4040
pub enum OauthTokenType {
4141
/// Bearer
4242
#[default]
@@ -47,7 +47,7 @@ pub enum OauthTokenType {
4747
Debug, Clone, Copy, PartialEq, Default, EnumIter, Display, AsRefStr, Serialize, Deserialize,
4848
)]
4949
#[strum(serialize_all = "snake_case")]
50-
#[serde(rename_all = "snake_case", untagged)]
50+
#[serde(rename_all = "snake_case")]
5151
pub enum OauthScopeType {
5252
/// 全局
5353
#[default]

0 commit comments

Comments
 (0)