Skip to content

Commit 93c0cfe

Browse files
committed
📝 增加日志记录设施,记录登录行为。
1 parent a764d3a commit 93c0cfe

File tree

6 files changed

+112
-22
lines changed

6 files changed

+112
-22
lines changed

packages/database/src/models/system/sys_action_log.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use sea_orm::entity::prelude::*;
22
use serde::{Deserialize, Serialize};
33

4-
use _utils::types::SystemActionLogAction;
4+
use _utils::types::{SysActionLogExtra, SystemActionLogAction};
55

66
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
77
#[sea_orm(table_name = "sys_action_log", schema_name = "genshin_map")]
@@ -33,8 +33,8 @@ pub struct Model {
3333
/// 是否发生错误
3434
pub is_error: bool,
3535
/// 附加信息
36-
/// TODO: 原客户端的设计中,这个值似乎总是为 {"accessPaths":[]}
37-
pub extra_data: Option<serde_json::Value>,
36+
#[sea_orm(column_type = "Json")]
37+
pub extra_data: SysActionLogExtra,
3838
}
3939

4040
#[derive(Debug, Clone, Copy, EnumIter, DeriveRelation)]

packages/database/src/models/system/sys_user.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use sea_orm::entity::prelude::*;
22
use serde::{Deserialize, Serialize};
33

4-
use _utils::types::SystemUserRole;
4+
use _utils::types::{AccessPolicyList, SystemUserRole};
55

66
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
77
#[sea_orm(table_name = "sys_user", schema_name = "genshin_map")]
@@ -42,7 +42,8 @@ pub struct Model {
4242
/// 角色 ID
4343
pub role_id: SystemUserRole,
4444
/// 权限策略
45-
pub access_policy: Option<serde_json::Value>,
45+
#[sea_orm(column_type = "Json")]
46+
pub access_policy: AccessPolicyList,
4647
/// 备注
4748
pub remark: Option<String>,
4849
}

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

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
11
use anyhow::{anyhow, Result};
2+
use std::net::SocketAddr;
23

34
use redis::{AsyncTypedCommands, SetOptions};
4-
use sea_orm::prelude::*;
5+
use sea_orm::{prelude::*, ActiveValue::Set};
56

67
use _database::{models, DB_CONN};
78
use _utils::{
89
bcrypt::verify_hash,
910
jwt::{generate_token, EXPIRED_APPEND_DURATION},
10-
types::auth::{OauthAnonymousResponse, OauthLoginResponse, OauthScopeType, OauthTokenType},
11+
types::{
12+
auth::{OauthAnonymousResponse, OauthLoginResponse, OauthScopeType, OauthTokenType},
13+
SystemActionLogAction,
14+
},
1115
};
1216

13-
pub async fn oauth_password_login(
14-
username: String,
15-
password: String,
17+
async fn oauth_password_login_inner(
18+
item: models::system::sys_user::Model,
19+
password_raw: String,
1620
) -> Result<OauthLoginResponse> {
17-
let item = models::system::sys_user::Entity::find()
18-
.filter(models::system::sys_user::Column::DelFlag.eq(false))
19-
.filter(models::system::sys_user::Column::Username.eq(username))
20-
.one(&DB_CONN.wait().pg_conn)
21-
.await?
22-
.ok_or(anyhow!("User not found"))?;
23-
2421
if !verify_hash(
25-
password,
22+
password_raw,
2623
item.password
2724
.strip_prefix("{bcrypt}")
2825
.ok_or(anyhow!("Failed to strip bcrypt prefix"))?,
@@ -73,6 +70,38 @@ pub async fn oauth_password_login(
7370
})
7471
}
7572

73+
pub async fn oauth_password_login(
74+
username: String,
75+
password_raw: String,
76+
ip: SocketAddr,
77+
user_agent: String,
78+
) -> Result<OauthLoginResponse> {
79+
let item = models::system::sys_user::Entity::find()
80+
.filter(models::system::sys_user::Column::DelFlag.eq(false))
81+
.filter(models::system::sys_user::Column::Username.eq(username))
82+
.one(&DB_CONN.wait().pg_conn)
83+
.await?
84+
.ok_or(anyhow!("User not found"))?;
85+
let user_id = item.id;
86+
87+
// TODO: 根据 access_policy 指定的模式,对请求做各种检查
88+
let ret = oauth_password_login_inner(item, password_raw).await;
89+
90+
models::system::sys_action_log::ActiveModel {
91+
user_id: Set(Some(user_id)),
92+
ipv4: Set(Some(ip.to_string())),
93+
device_id: Set(user_agent),
94+
action: Set(SystemActionLogAction::Login),
95+
is_error: Set(ret.is_err()),
96+
extra_data: Set(Default::default()),
97+
..Default::default()
98+
}
99+
.insert(&DB_CONN.wait().pg_conn)
100+
.await?;
101+
102+
ret
103+
}
104+
76105
pub async fn oauth_client_credentials(scope: String) -> Result<OauthAnonymousResponse> {
77106
// Handle client credentials grant type
78107
todo!()

packages/router/src/routes/system/oauth.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use serde::Deserialize;
33
use std::{collections::HashMap, net::SocketAddr};
44

55
use axum::{
6-
extract::{ConnectInfo, Form, Json, Multipart, Query},
6+
extract::{ConnectInfo, Json, Multipart, Query},
77
http::StatusCode,
88
response::IntoResponse,
99
};
@@ -78,7 +78,7 @@ pub async fn oauth(
7878
.remove("password")
7979
.ok_or((StatusCode::BAD_REQUEST, "Password is required".into()))?;
8080
return Ok(Json(
81-
oauth_password_login(username, password)
81+
oauth_password_login(username, password, ip, user_agent)
8282
.await
8383
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))?,
8484
)

packages/utils/src/types/auth.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use strum::{AsRefStr, Display, EnumIter};
33
use uuid::Uuid;
44

55
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6+
#[serde(rename_all = "snake_case")]
67
pub struct OauthLoginResponse {
78
/// 访问令牌
89
pub access_token: String,
@@ -19,6 +20,7 @@ pub struct OauthLoginResponse {
1920
}
2021

2122
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23+
#[serde(rename_all = "snake_case")]
2224
pub struct OauthAnonymousResponse {
2325
/// 访问令牌
2426
pub access_token: String,

packages/utils/src/types/system.rs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use serde::{Deserialize, Serialize};
2-
use strum::EnumIter;
2+
use strum::{AsRefStr, Display, EnumIter, EnumString};
33

4-
use sea_orm::prelude::*;
4+
use sea_orm::{prelude::*, FromJsonQueryResult};
55

66
use super::HiddenFlag;
77

@@ -13,6 +13,64 @@ pub enum SystemActionLogAction {
1313
Login,
1414
}
1515

16+
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, FromJsonQueryResult)]
17+
#[serde(rename_all = "camelCase")]
18+
pub struct SysActionLogExtra {
19+
pub access_paths: Vec<AccessPolicyItem>,
20+
}
21+
22+
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, FromJsonQueryResult)]
23+
pub struct AccessPolicyList(pub Vec<AccessPolicyItemEnum>);
24+
25+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, FromJsonQueryResult)]
26+
#[serde(rename_all = "camelCase")]
27+
pub struct AccessPolicyItem {
28+
pub passed: bool,
29+
pub policy: AccessPolicyItemEnum,
30+
}
31+
32+
#[derive(
33+
Debug, Clone, Copy, PartialEq, Serialize, Deserialize, EnumIter, AsRefStr, EnumString, Display,
34+
)]
35+
pub enum AccessPolicyItemEnum {
36+
/// 与最后一次登录 IP 相同
37+
#[strum(serialize = "ip:same_last_ip")]
38+
#[serde(rename = "ip:same_last_ip")]
39+
IpSameLastIp,
40+
/// 对列表中有效的 IP 放行
41+
#[strum(serialize = "ip:pass_allow_ip")]
42+
#[serde(rename = "ip:pass_allow_ip")]
43+
IpPassAllowIp,
44+
/// 对列表中禁用的 IP 拦截
45+
#[strum(serialize = "ip:block_disallow_ip")]
46+
#[serde(rename = "ip:block_disallow_ip")]
47+
IpBlockDisallowIp,
48+
/// 与最后一次登录地区相同
49+
#[strum(serialize = "ip:same_last_region")]
50+
#[serde(rename = "ip:same_last_region")]
51+
IpSameLastRegion,
52+
/// 对列表中有效的地区放行
53+
#[strum(serialize = "ip:pass_allow_region")]
54+
#[serde(rename = "ip:pass_allow_region")]
55+
IpPassAllowRegion,
56+
/// 对列表中禁用的地区拦截
57+
#[strum(serialize = "ip:block_disallow_region")]
58+
#[serde(rename = "ip:block_disallow_region")]
59+
IpBlockDisallowRegion,
60+
/// 与最后一次登录设备相同
61+
#[strum(serialize = "dev:same_last_device")]
62+
#[serde(rename = "dev:same_last_device")]
63+
DevSameLastDevice,
64+
/// 对列表中有效的设备放行
65+
#[strum(serialize = "dev:pass_allow_device")]
66+
#[serde(rename = "dev:pass_allow_device")]
67+
DevPassAllowDevice,
68+
/// 对列表中禁用的设备拦截
69+
#[strum(serialize = "dev:block_disallow_device")]
70+
#[serde(rename = "dev:block_disallow_device")]
71+
DevBlockDisallowDevice,
72+
}
73+
1674
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, EnumIter, DeriveActiveEnum)]
1775
#[sea_orm(rs_type = "i32", db_type = "Integer")]
1876
pub enum SystemUserRole {

0 commit comments

Comments
 (0)