master
git 2 years ago
parent ec228c63e3
commit 21701e405e

630
oab/Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -12,15 +12,15 @@ serde = { version = "1", features = ["derive"] }
serde_json = "*" serde_json = "*"
serde_yaml = "*" serde_yaml = "*"
clap = { version = "3", features = ["derive"] } clap = { version = "3", features = ["derive"] }
chrono = "0.4" chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
futures-util = "*" futures-util = "*"
tracing = "*" tracing = "*"
tracing-subscriber = "*" tracing-subscriber = "*"
thiserror = "1.0" thiserror = "1.0"
rbson = "2" sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "mysql", "macros", "migrate", "chrono"] }
rbatis = { version = "*", default-features = false, features = ["runtime-tokio-rustls","mysql","debug_mode"] }
actix-web = "4" actix-web = "4"
jsonwebtoken = "8" jsonwebtoken = "8"
@ -30,3 +30,5 @@ block-padding = "0.3.2"
generic-array = "0.14.5" generic-array = "0.14.5"
serde-big-array = "0.4.1" serde-big-array = "0.4.1"
base64 = "0.13.0" base64 = "0.13.0"
uuid = { version = "1.1", features = ["v3","v4", "fast-rng", "macro-diagnostics"]}

@ -40,7 +40,7 @@ CREATE TABLE IF NOT EXISTS `app`
`des` varchar(255), `des` varchar(255),
`user_count` int NOT NULL DEFAULT 0, `user_count` int NOT NULL DEFAULT 0,
`hide` tinyint(1) NOT NULL DEFAULT 0, `hide` tinyint(1) NOT NULL DEFAULT 0,
`join_method` enum('auto','disabled','applying') NOT NULL DEFAULT 'auto', `join_method` int NOT NULL DEFAULT 0,
`role_id` varchar(32), `role_id` varchar(32),
`redirect` varchar(255), `redirect` varchar(255),
@ -56,7 +56,7 @@ CREATE TABLE IF NOT EXISTS `app_user`
`app_id` varchar(32) NOT NULL, `app_id` varchar(32) NOT NULL,
`user_id` varchar(32) NOT NULL, `user_id` varchar(32) NOT NULL,
`status` enum('ok', 'disabled', 'applying', 'deny') NOT NULL, `status` int NOT NULL DEFAULT 0,
PRIMARY KEY (`user_id`,`app_id`) USING BTREE, PRIMARY KEY (`user_id`,`app_id`) USING BTREE,
FOREIGN KEY (`app_id`) REFERENCES `app`(`id`), FOREIGN KEY (`app_id`) REFERENCES `app`(`id`),

@ -5,34 +5,36 @@
// Distributed under terms of the Apache license. // Distributed under terms of the Apache license.
// //
use crate::{dbtx, models, Error, Result, CONFIG, DB}; use std::fmt::{format, Debug};
use actix_web::{delete, get, head, post, web, Responder};
use crate::{models, Error, Result, CONFIG};
use actix_web::{delete, get, head, http, post, web, HttpResponse, Responder};
use base64; use base64;
use rbatis::crud::CRUD;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::info; use tracing::info;
use uuid::uuid;
#[get("/user/{id}")] #[get("/user/{id}")]
pub async fn get(id: web::Path<String>) -> Result<models::User> { pub async fn get(id: web::Path<String>) -> Result<models::User> {
let n = id.into_inner(); let n = id.into_inner();
if !n.is_empty() { if !n.is_empty() {
let u: Option<models::User> = DB.fetch_by_column("id", &n).await?; let s = sqlx::query_as::<_, models::User>("select *& from user where id = ?")
match u { .bind(n)
Some(u) => { .fetch_one(CONFIG.db())
info!("{:#?}", u.token()); .await?;
return Ok(u); info!("{:#?}", s);
} Ok(s)
None => Err(Error::NotFound(format!("user {}", n))),
}
} else { } else {
Err(Error::Missing("id".to_string())) Err(Error::Missing("id".to_string()))
} }
} }
#[get("/user/")] #[get("/user/")]
pub async fn list() -> impl Responder { pub async fn list() -> Result<impl Responder> {
let result: Vec<models::User> = DB.fetch_list().await.unwrap(); let result = sqlx::query_as::<_, models::User>("select * from user")
web::Json(result) .fetch_all(CONFIG.db())
.await?;
Ok(web::Json(result))
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
@ -42,18 +44,97 @@ pub struct LoginOpt {
} }
#[head("/user/{id}")] #[head("/user/{id}")]
pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> impl Responder { pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> Result<HttpResponse> {
let id = id.into_inner(); let id = id.into_inner();
let q = q.into_inner(); let q = q.into_inner();
info!("{} try to login{:#?}", id, q); let typ = match q.typ {
let mut w = DB.new_wrapper(); Some(t) => match t.as_str() {
match q.typ { "phone" => "phone",
_ => w = w.eq("username", id), "email" => "email",
_ => "username",
},
_ => "username",
};
let p = match base64::decode(q.password.as_bytes()) {
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
Ok(p) => p,
};
let p = match std::str::from_utf8(&p) {
Ok(p) => p,
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
};
let sql = format!("select * from user where {} = ?", typ);
let u = sqlx::query_as::<_, models::User>(&sql)
.bind(id)
.fetch_optional(CONFIG.db())
.await?;
let u = match u {
Some(u) => u,
None => return Err(Error::NotFound("user".to_string())),
};
u.check_pass(p)?;
let au = sqlx::query_as::<_, models::AppUser>(
"select * from app_user where app_id = ? and user_id = ?",
)
.bind(&CONFIG.uuid)
.bind(&u.id)
.fetch_optional(CONFIG.db())
.await?;
let i: i64 = match au {
Some(au) => match au.status {
models::AUStatus::OK => 0,
models::AUStatus::Deny => {
return Err(Error::BusinessException("apply denied".to_string()))
} }
let u: Option<models::User> = DB.fetch_by_wrapper(w).await.unwrap(); models::AUStatus::Disabled => {
return Err(Error::BusinessException("login disabled".to_string()))
}
models::AUStatus::Applying => {
return Err(Error::BusinessException("applying".to_string()))
}
},
None => {
let app = sqlx::query_as::<_, models::App>("select * from app where id = ?")
.bind(CONFIG.uuid.clone())
.fetch_one(CONFIG.db())
.await?;
info!("{:#?}", u); info!("{:#?}", u);
let s = match app.join_method {
"" models::app::AppJoin::Disabled => {
return Err(Error::BusinessException(
"this app diabled login".to_string(),
))
}
models::app::AppJoin::Auto => models::AUStatus::OK,
models::app::AppJoin::Applying => models::AUStatus::Applying,
};
sqlx::query(
r#"
insert into app_user (app_id,user_id,status)
values ( ?, ?, ? )
"#,
)
.bind(&app.id)
.bind(&u.id)
.bind(&s)
.execute(CONFIG.db())
.await?;
match s {
models::AUStatus::OK => 0,
_ => 1,
}
}
};
if i == 0 {
Ok(HttpResponse::build(http::StatusCode::OK)
.insert_header(("auth_token", u.token().to_string()?))
.body("".to_string()))
} else {
Ok(HttpResponse::build(http::StatusCode::OK)
.insert_header(("data", "applying"))
.body("".to_string()))
}
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
@ -67,7 +148,11 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
let q = q.into_inner(); let q = q.into_inner();
// let mut tx = dbtx().await; // let mut tx = dbtx().await;
println!("{:#?}", q); println!("{:#?}", q);
let u: Option<models::User> = DB.fetch_by_column("username", &q.username).await.unwrap(); let u: Option<models::User> =
sqlx::query_as::<_, models::User>("select * from user where username = ?")
.bind(q.username.clone())
.fetch_optional(CONFIG.db())
.await?;
let u: models::User = match u { let u: models::User = match u {
Some(_) => return Err(Error::ArgDuplicated(format!("username: {}", q.username))), Some(_) => return Err(Error::ArgDuplicated(format!("username: {}", q.username))),
None => { None => {
@ -86,8 +171,11 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
u u
} }
}; };
let oa: Option<models::App> = DB.fetch_by_column("id", CONFIG.uuid.clone()).await?; let oa: models::App = sqlx::query_as::<_, models::App>("select * from app where id = ?")
let oa = oa.unwrap(); .bind(CONFIG.uuid.clone())
.fetch_one(CONFIG.db())
.await?;
let mut au = models::AppUser::new(); let mut au = models::AppUser::new();
au.app_id = oa.id; au.app_id = oa.id;
au.user_id = u.id.clone(); au.user_id = u.id.clone();
@ -96,8 +184,31 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
models::app::AppJoin::Auto => au.status = models::app::AUStatus::OK, models::app::AppJoin::Auto => au.status = models::app::AUStatus::OK,
models::app::AppJoin::Applying => au.status = models::app::AUStatus::Applying, models::app::AppJoin::Applying => au.status = models::app::AUStatus::Applying,
} }
DB.save(&u, &[]).await?; let mut c = CONFIG.db().begin().await?;
DB.save(&au, &[]).await?; sqlx::query!(
r#"
insert into user (id,username,real_code,check_code)
values ( ?, ?, ?, ?)
"#,
u.id,
u.username,
u.real_code,
u.check_code,
)
.execute(&mut c)
.await?;
sqlx::query!(
r#"
insert into app_user ( app_id, user_id, status)
values (?, ?, ? )
"#,
au.app_id,
au.user_id,
au.status,
)
.execute(&mut c)
.await?;
c.commit().await?;
Ok("ok".to_string()) Ok("ok".to_string())
} }

@ -16,12 +16,8 @@ use std::{
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rbatis::{logic_delete::RbatisLogicDeletePlugin, rbatis::Rbatis}; use sqlx::{mysql::MySqlPoolOptions, Pool};
use tracing::log::warn; use tracing::log::warn;
lazy_static! {
// Rbatis是线程、协程安全的运行时的方法是Send+Sync无需担心线程竞争
pub static ref DB:Rbatis= new_db();
}
lazy_static! { lazy_static! {
pub static ref CLI: AppCli = AppCli::new(); pub static ref CLI: AppCli = AppCli::new();
@ -60,7 +56,7 @@ impl AppCli {
} }
} }
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct ApplicationConfig { pub struct ApplicationConfig {
pub uuid: String, pub uuid: String,
pub key: String, pub key: String,
@ -76,28 +72,35 @@ pub struct ApplicationConfig {
pub log_pack_compress: Option<String>, pub log_pack_compress: Option<String>,
pub log_level: Option<String>, pub log_level: Option<String>,
pub jwt_secret: Option<String>, pub jwt_secret: Option<String>,
#[serde(skip)]
pub _pool: Option<Pool<sqlx::MySql>>,
} }
impl ApplicationConfig { impl ApplicationConfig {
pub fn new() -> Self { pub fn new() -> Self {
let mut res = Self::defaut();
let mut f = match File::open(CLI.cfg.clone()) { let mut f = match File::open(CLI.cfg.clone()) {
Ok(f) => f, Ok(f) => f,
Err(ref e) if e.kind() == io::ErrorKind::NotFound => return Self::defaut(), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
res._pool = Some(res.connect());
return res;
}
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
}; };
File::open(CLI.cfg.clone()).unwrap(); File::open(CLI.cfg.clone()).unwrap();
let mut yml_data = String::new(); let mut yml_data = String::new();
f.read_to_string(&mut yml_data).unwrap(); f.read_to_string(&mut yml_data).unwrap();
//读取配置 //读取配置
let result: ApplicationConfig = res = serde_yaml::from_str(&yml_data).expect("load config file fail");
serde_yaml::from_str(&yml_data).expect("load config file fail"); if res.debug {
if result.debug { println!("load config:{:?}", res);
println!("load config:{:?}", result);
println!("///////////////////// Start On Debug Mode ////////////////////////////"); println!("///////////////////// Start On Debug Mode ////////////////////////////");
} else { } else {
println!("release_mode is enable!") println!("release_mode is enable!")
} }
result res._pool = Some(res.connect());
res
} }
pub fn defaut() -> Self { pub fn defaut() -> Self {
Self { Self {
@ -114,39 +117,29 @@ impl ApplicationConfig {
log_pack_compress: None, log_pack_compress: None,
log_level: None, log_level: None,
jwt_secret: None, jwt_secret: None,
_pool: None,
} }
} }
pub fn save(&self) {} pub fn save(&self) {}
pub fn db(&self) -> &DB { pub fn db(&self) -> &sqlx::MySqlPool {
DB.borrow() match &self._pool {
Some(d) => d,
None => panic!("failed"),
}
} }
pub async fn connect(&self) { fn connect(&self) -> Pool<sqlx::MySql> {
let url = format!( let url = format!(
"mysql://{}:{}@{}/{}", "mysql://{}:{}@{}/{}",
self.db_user, self.db_pass, self.db_url, self.db_name self.db_user, self.db_pass, self.db_url, self.db_name
); );
DB.link(&url).await.unwrap(); let p = MySqlPoolOptions::new()
.max_connections(5)
.connect_lazy(&url)
.unwrap();
p
} }
} }
fn new_db() -> rbatis::rbatis::Rbatis {
let mut rb = rbatis::rbatis::Rbatis::new();
rb.logic_plugin = Some(Box::new(RbatisLogicDeletePlugin::new("delete_flag")));
rb
}
pub async fn dbtx() -> rbatis::executor::RBatisTxExecutorGuard<'static> {
DB.acquire_begin()
.await
.unwrap()
.defer_async(|mut tx1| async move {
if !tx1.is_done() {
_ = tx1.rollback().await;
warn!("db rollback!")
}
})
}
struct FormatTime; struct FormatTime;
impl tracing_subscriber::fmt::time::FormatTime for FormatTime { impl tracing_subscriber::fmt::time::FormatTime for FormatTime {
fn format_time(&self, w: &mut tracing_subscriber::fmt::format::Writer<'_>) -> std::fmt::Result { fn format_time(&self, w: &mut tracing_subscriber::fmt::format::Writer<'_>) -> std::fmt::Result {

@ -10,5 +10,5 @@ mod cfg;
pub mod libs; pub mod libs;
pub mod models; pub mod models;
mod result; mod result;
pub use cfg::{dbtx, init_log, ApplicationConfig, Clis, CLI, CONFIG, DB}; pub use cfg::{init_log, ApplicationConfig, Clis, CLI, CONFIG};
pub use result::{Error, Result}; pub use result::{Error, Result};

@ -4,7 +4,11 @@
// 2022-07-07 23:51 // 2022-07-07 23:51
// Distributed under terms of the Apache license. // Distributed under terms of the Apache license.
// //
use actix_web::{middleware, web, App, HttpServer}; use actix_web::{
middleware,
web::{self, Data},
App, HttpServer,
};
use oab::{api, init_log, models, Clis, Result, CLI, CONFIG}; use oab::{api, init_log, models, Clis, Result, CLI, CONFIG};
use tracing::{info, warn}; use tracing::{info, warn};
@ -15,14 +19,12 @@ async fn main() -> Result<()> {
if let Some(c) = &CLI.command { if let Some(c) = &CLI.command {
match c { match c {
Clis::Init => { Clis::Init => {
CONFIG.connect().await;
models::init().await; models::init().await;
return Ok(()); return Ok(());
} }
_ => {} _ => {}
}; };
}; };
CONFIG.connect().await;
web().await?; web().await?;
Ok(()) Ok(())
} }
@ -49,6 +51,7 @@ async fn web() -> Result<()> {
.service( .service(
web::scope("api") web::scope("api")
.app_data(json_config) .app_data(json_config)
.app_data(Data::new(CONFIG.db()))
.configure(api::routes), .configure(api::routes),
) )
}); });

@ -5,29 +5,28 @@
// Distributed under terms of the Apache license. // Distributed under terms of the Apache license.
// //
use rbatis::{crud_table, DateTimeNative}; use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, sqlx::Type)]
#[serde(rename_all = "lowercase")] #[repr(i64)]
pub enum AppJoin { pub enum AppJoin {
Auto, Auto = 0,
Disabled, Disabled = 1,
Applying, Applying = 2,
} }
#[crud_table] #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
#[derive(Debug, Clone)]
pub struct App { pub struct App {
pub id: String, pub id: String,
pub created: Option<DateTimeNative>, pub created: Option<NaiveDateTime>,
pub updated: Option<DateTimeNative>, pub updated: Option<NaiveDateTime>,
pub delete_flag: bool, pub delete_flag: bool,
pub name: Option<String>, pub name: Option<String>,
pub des: Option<String>, pub des: Option<String>,
pub icon: Option<String>, pub icon: Option<String>,
pub user_count: usize, pub user_count: i64,
pub hide: bool, pub hide: bool,
pub join_method: AppJoin, pub join_method: AppJoin,
@ -40,7 +39,7 @@ pub struct App {
impl App { impl App {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
id: rbatis::plugin::object_id::ObjectId::new().to_string(), id: "".to_string(),
created: None, created: None,
updated: None, updated: None,
delete_flag: false, delete_flag: false,
@ -58,20 +57,19 @@ impl App {
} }
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone, sqlx::Type)]
#[serde(rename_all = "lowercase")] #[repr(i64)]
pub enum AUStatus { pub enum AUStatus {
OK, OK = 0,
Disabled, Disabled = 1,
Applying, Applying = 2,
Deny, Deny = 3,
} }
#[crud_table] #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AppUser { pub struct AppUser {
pub created: Option<DateTimeNative>, pub created: Option<NaiveDateTime>,
pub updated: Option<DateTimeNative>, pub updated: Option<NaiveDateTime>,
pub app_id: String, pub app_id: String,
pub user_id: String, pub user_id: String,
pub status: AUStatus, pub status: AUStatus,

@ -8,23 +8,16 @@
pub mod app; pub mod app;
mod role; mod role;
mod user; mod user;
use std::{fs::File, io::Read};
use tracing::info; use tracing::info;
use crate::DB;
pub use app::{AUStatus, App, AppUser}; pub use app::{AUStatus, App, AppUser};
pub use role::{Access, Resource, Role}; pub use role::{Access, Resource, Role};
pub use user::User; pub use user::User;
use crate::CONFIG;
pub async fn init() { pub async fn init() {
info!("init database"); info!("init database");
let mut f = File::open("./sql/table.sql").unwrap(); sqlx::migrate!().run(CONFIG.db()).await.unwrap();
let mut sql = String::new();
f.read_to_string(&mut sql).unwrap();
DB.exec(&sql, vec![]).await.unwrap();
}
pub fn new_id() -> rbatis::object_id::ObjectId {
rbatis::plugin::object_id::ObjectId::new()
} }

@ -4,14 +4,15 @@
// 2022-07-09 02:42 // 2022-07-09 02:42
// Distributed under terms of the Apache license. // Distributed under terms of the Apache license.
// //
use rbatis::{crud_table, DateTimeNative};
#[crud_table] use chrono::NaiveDateTime;
#[derive(Debug, Clone, Default)] use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Role { pub struct Role {
pub id: String, pub id: String,
pub created: Option<DateTimeNative>, pub created: Option<NaiveDateTime>,
pub updated: Option<DateTimeNative>, pub updated: Option<NaiveDateTime>,
pub delete_flag: bool, pub delete_flag: bool,
pub app_id: String, pub app_id: String,
@ -20,11 +21,10 @@ pub struct Role {
pub user_count: usize, pub user_count: usize,
} }
#[crud_table] #[derive(Debug, Default, Serialize, Deserialize)]
#[derive(Debug, Clone, Default)]
pub struct Resource { pub struct Resource {
pub created: Option<DateTimeNative>, pub created: Option<NaiveDateTime>,
pub updated: Option<DateTimeNative>, pub updated: Option<NaiveDateTime>,
pub delete_flag: bool, pub delete_flag: bool,
pub app_id: String, pub app_id: String,
@ -32,11 +32,10 @@ pub struct Resource {
pub des: Option<String>, pub des: Option<String>,
} }
#[crud_table] #[derive(Debug, Default, Serialize, Deserialize)]
#[derive(Debug, Clone, Default)]
pub struct Access { pub struct Access {
pub created: Option<DateTimeNative>, pub created: Option<NaiveDateTime>,
pub updated: Option<DateTimeNative>, pub updated: Option<NaiveDateTime>,
pub delete_flag: bool, pub delete_flag: bool,
pub app_id: String, pub app_id: String,

@ -7,11 +7,9 @@
// //
use actix_web::ResponseError; use actix_web::ResponseError;
use chrono::{prelude::*, Duration};
use generic_array::typenum::U32; use chrono::{prelude::*, Duration};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use rbatis::{crud_table, DateTimeNative};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::info; use tracing::info;
@ -20,7 +18,8 @@ use aes_gcm::aead::{Aead, NewAead};
use aes_gcm::{Aes256Gcm, Key, Nonce}; use aes_gcm::{Aes256Gcm, Key, Nonce};
use block_padding::{Padding, Pkcs7}; use block_padding::{Padding, Pkcs7};
use generic_array::{ArrayLength, GenericArray}; use generic_array::typenum::U32;
use generic_array::GenericArray;
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
@ -44,12 +43,11 @@ fn rand_str(l: usize) -> String {
// block // block
// } // }
#[crud_table] #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
#[derive(Debug, Clone)]
pub struct User { pub struct User {
pub id: String, pub id: String,
pub created: Option<DateTimeNative>, pub created: Option<NaiveDateTime>,
pub updated: Option<DateTimeNative>, pub updated: Option<NaiveDateTime>,
pub delete_flag: bool, pub delete_flag: bool,
pub username: String, pub username: String,
@ -58,10 +56,10 @@ pub struct User {
pub phone: Option<String>, pub phone: Option<String>,
pub icon: Option<String>, pub icon: Option<String>,
pub real_code: Option<String>, pub real_code: Option<String>,
pub check_code: Option<rbatis::Bytes>, pub check_code: Option<Vec<u8>>,
pub status: usize, pub status: i32,
pub used: usize, pub used: i32,
pub space: usize, pub space: i32,
} }
impl User { impl User {
@ -75,6 +73,30 @@ impl User {
}; };
t t
} }
pub fn check_pass(&self, p: &str) -> Result<()> {
let p = p.as_bytes();
let mut key_block: GenericArray<u8, U32> = [0xff; 32].into();
key_block[..p.len()].copy_from_slice(p);
Pkcs7::pad(&mut key_block, p.len());
// key 32 Byte
let key = Key::from_slice(&key_block);
let cipher = Aes256Gcm::new(&key);
// 12 Byte
// 96-bits; unique per message
let nonce = Nonce::from_slice(&self.id.as_bytes()[..12]);
let plaintext = match cipher.decrypt(nonce, self.check_code.as_ref().unwrap().as_slice()) {
Ok(p) => p,
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
};
let plaintext = std::str::from_utf8(&plaintext).unwrap();
if plaintext.eq(self.real_code.as_ref().unwrap()) {
Ok(())
} else {
Err(Error::ArgInvalid("password".to_string()))
}
}
pub fn update_pass(&mut self, p: &str) -> Result<()> { pub fn update_pass(&mut self, p: &str) -> Result<()> {
if p.len() < 6 || p.len() > 32 { if p.len() < 6 || p.len() > 32 {
return Err(Error::ArgInvalid("password".to_string())); return Err(Error::ArgInvalid("password".to_string()));
@ -107,8 +129,8 @@ impl User {
impl Default for User { impl Default for User {
fn default() -> Self { fn default() -> Self {
Self { Self {
id: rbatis::plugin::object_id::ObjectId::new().to_string(), id: uuid::Uuid::new_v4().to_string().replace("-", ""),
created: Some(DateTimeNative::now()), created: None,
updated: None, updated: None,
delete_flag: false, delete_flag: false,

@ -16,6 +16,7 @@ use actix_web::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
use tracing::info;
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
@ -114,13 +115,13 @@ impl From<actix_web::Error> for Error {
Error::BusinessException(format!("{:?}", e)) Error::BusinessException(format!("{:?}", e))
} }
} }
impl From<jsonwebtoken::errors::Error> for Error { impl From<sqlx::Error> for Error {
fn from(e: jsonwebtoken::errors::Error) -> Self { fn from(e: sqlx::Error) -> Self {
Error::BusinessException(format!("{:?}", e)) Error::BusinessException(format!("{:?}", e))
} }
} }
impl From<rbatis::error::Error> for Error { impl From<jsonwebtoken::errors::Error> for Error {
fn from(e: rbatis::error::Error) -> Self { fn from(e: jsonwebtoken::errors::Error) -> Self {
Error::BusinessException(format!("{:?}", e)) Error::BusinessException(format!("{:?}", e))
} }
} }
@ -145,9 +146,11 @@ impl actix_web::Responder for Error {
impl error::ResponseError for Error { impl error::ResponseError for Error {
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> HttpResponse {
info!("{}", self.to_string());
HttpResponse::build(self.status_code()) HttpResponse::build(self.status_code())
.insert_header(ContentType::html()) .insert_header(ContentType::html())
.body(self.to_string()) .insert_header(("error", self.to_string()))
.body("".to_string())
} }
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {

@ -29,19 +29,14 @@ function baseRequests(url: string, method: any = 'GET', query: any, data: any, s
method: method, method: method,
headers: headers, headers: headers,
}).then((res: any) => { }).then((res: any) => {
if ('auth_token' in res.headers) {
localStorage.auth_token = res.headers.auth_token
store.commit('user/refreshToken', localStorage.auth_token)
}
if ('redirect_url' in res.headers) { if ('redirect_url' in res.headers) {
window.location.href = res.headers.redirect_url window.location.href = res.headers.redirect_url
return return
} }
console.log(res)
if (method === 'HEAD') { if (method === 'HEAD') {
success(res.headers) success(res.headers)
} else { } else {
success(res) success(res.data)
} }
}) })
.catch((e: any) => { .catch((e: any) => {
@ -51,7 +46,7 @@ function baseRequests(url: string, method: any = 'GET', query: any, data: any, s
} }
let code = e.response.status let code = e.response.status
if (code === 400) { if (code === 400) {
msg.Warn(e.response.data) msg.Warn(e.response.headers.error)
return return
} else if (code === 401) { } else if (code === 401) {
console.log(e) console.log(e)

@ -1,9 +1,9 @@
<template> <template>
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<div <div :style="{ background: Theme.me.lightBox, 'box-shadow': Theme.me.lightBoxShadow }"
:style="{background:Theme.me.lightBox, 'box-shadow': Theme.me.lightBoxShadow}"
class="px-10 pb-9 pt-28 rounded-xl w-96"> class="px-10 pb-9 pt-28 rounded-xl w-96">
<n-form label-width="70px" label-align="left" :model="data" ref="form_ref" label-placement="left" :rules="rules"> <n-form label-width="70px" label-align="left" :model="data" ref="form_ref" label-placement="left"
:rules="rules">
<n-form-item required label="用户名" path="username"> <n-form-item required label="用户名" path="username">
<n-input @keydown.enter="divs[1].focus()" :ref="el => { if (el) divs[0] = el }" <n-input @keydown.enter="divs[1].focus()" :ref="el => { if (el) divs[0] = el }"
v-model:value="data.username"></n-input> v-model:value="data.username"></n-input>
@ -23,14 +23,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
import { Theme } from '@/theme' import { Theme } from '@/theme'
import {useMessage} from 'naive-ui'
import api from '@/api' import api from '@/api'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { store } from '@/store' import { store } from '@/store'
import { modelsApp } from '@/models' import { modelsApp } from '@/models'
import util from '@/libs/util' import util from '@/libs/util'
import msg from '@veypi/msg'
let msg = useMessage()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@ -69,13 +68,20 @@ function login() {
// @ts-ignore // @ts-ignore
form_ref.value.validate((e: any) => { form_ref.value.validate((e: any) => {
if (!e) { if (!e) {
api.user.login(data.value.username, data.value.password).Start((url: string) => { api.user.login(data.value.username, data.value.password).Start((headers: any) => {
msg.success('登录成功') if ('auth_token' in headers) {
localStorage.auth_token = headers.auth_token
store.commit('user/refreshToken', localStorage.auth_token)
msg.Info('登录成功')
store.dispatch('user/fetchUserData') store.dispatch('user/fetchUserData')
redirect(route.query.redirect as string) redirect(route.query.redirect as string)
} else {
msg.Info('正在申请加入,请等待管理员审批')
}
console.log(headers)
}, e => { }, e => {
console.log(e) console.log(e)
msg.warning('登录失败:' + e) msg.Warn('登录失败:' + e.headers.error)
}) })
} }
}) })

Loading…
Cancel
Save