auth loop complete
This commit is contained in:
parent
d7b4a45a9a
commit
08accea6af
|
|
@ -15,7 +15,6 @@ candle-nn = "0.5.1"
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
http = "1.1.0"
|
http = "1.1.0"
|
||||||
mongodb = { version = "2.8.2", features = ["bson-chrono-0_4", "tokio-runtime"]}
|
mongodb = { version = "2.8.2", features = ["bson-chrono-0_4", "tokio-runtime"]}
|
||||||
rlg = "0.0.4"
|
|
||||||
serde = "1.0.203"
|
serde = "1.0.203"
|
||||||
tokio = "1.38.0"
|
tokio = "1.38.0"
|
||||||
vrd = "0.0.7"
|
vrd = "0.0.7"
|
||||||
|
|
|
||||||
119
src/account.rs
119
src/account.rs
|
|
@ -2,41 +2,26 @@ pub mod db;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
body::Body,
|
||||||
extract::Path,
|
|
||||||
Json,
|
Json,
|
||||||
response::Response,
|
response::Response,
|
||||||
Router,
|
Router,
|
||||||
routing::{get, post}
|
routing::{get, post}
|
||||||
};
|
};
|
||||||
use axum_session_auth::AuthSession;
|
|
||||||
use axum_session_mongo::SessionMongoPool;
|
|
||||||
use chrono::Utc;
|
|
||||||
use crate::AppError;
|
use crate::AppError;
|
||||||
use db::{get_users, User};
|
use db::{get_users, User};
|
||||||
use http::StatusCode;
|
use http::{header::HeaderMap, StatusCode};
|
||||||
use mongodb::{
|
use mongodb::bson::{doc, oid::ObjectId};
|
||||||
bson::{doc, oid::ObjectId, to_document},
|
|
||||||
Client
|
|
||||||
};
|
|
||||||
use rlg::macro_info_log;
|
|
||||||
|
|
||||||
type AuthenticationSession = AuthSession<User, ObjectId, SessionMongoPool, Client>;
|
|
||||||
type ApiResult = Result<Response, AppError>;
|
type ApiResult = Result<Response, AppError>;
|
||||||
|
|
||||||
pub fn router() -> Router {
|
pub fn router() -> Router {
|
||||||
Router::new()
|
|
||||||
.nest("/:user_id", user_router())
|
|
||||||
.route("/sign-up",
|
|
||||||
post(post_sign_up)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn user_router() -> Router {
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/sign-in",
|
.route("/sign-in",
|
||||||
get(get_sign_in)
|
get(get_sign_in)
|
||||||
.post(post_sign_in)
|
.post(post_sign_in)
|
||||||
)
|
)
|
||||||
|
.route("/sign-up",
|
||||||
|
post(post_sign_up))
|
||||||
.route("/sign-out",
|
.route("/sign-out",
|
||||||
post(post_sign_out))
|
post(post_sign_out))
|
||||||
.route("/backup",
|
.route("/backup",
|
||||||
|
|
@ -47,24 +32,19 @@ fn user_router() -> Router {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_sign_in(Path(user_id): Path<ObjectId>) -> ApiResult {
|
pub async fn get_sign_in(Json(body): Json<User>) -> ApiResult {
|
||||||
let id = format!("user_id: {}", user_id);
|
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Salt request initiated");
|
|
||||||
|
|
||||||
let db = get_users().await?;
|
let db = get_users().await?;
|
||||||
let query = doc! { "_id" : user_id};
|
let query = doc! {
|
||||||
|
"$expr": { "$eq": ["$username", body.username] }
|
||||||
|
};
|
||||||
|
|
||||||
match db.find_one(query, None).await? {
|
match db.find_one(query, None).await? {
|
||||||
Some(user) => {
|
Some(user) => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Salt request successful");
|
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::CREATED)
|
.status(StatusCode::CREATED)
|
||||||
.body(Body::from(user.auth.salt.unwrap()))?)
|
.body(Body::from(user.auth.unwrap().salt.unwrap()))?)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Salt Request unsuccessful: username does not exist");
|
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::NOT_FOUND)
|
.status(StatusCode::NOT_FOUND)
|
||||||
.body(Body::from("User does not exist"))?)
|
.body(Body::from("User does not exist"))?)
|
||||||
|
|
@ -72,27 +52,32 @@ pub async fn get_sign_in(Path(user_id): Path<ObjectId>) -> ApiResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post_sign_in(Path(user_id): Path<ObjectId>, auth: AuthenticationSession, body: String) -> ApiResult {
|
pub async fn post_sign_in(Json(body): Json<User>) -> ApiResult {
|
||||||
let id = format!("user_id: {}", user_id);
|
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-in request initiated");
|
|
||||||
|
|
||||||
let db = get_users().await?;
|
let db = get_users().await?;
|
||||||
let query = doc! { "_id": &user_id, "_auth._hash": body };
|
let api = ObjectId::new();
|
||||||
|
let query = doc! {
|
||||||
|
"$expr": {
|
||||||
|
"$and": [
|
||||||
|
{ "$eq": ["$username", body.username]},
|
||||||
|
{ "$eq": ["$_auth._hash", body.auth.unwrap_or_default().hash]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let update = doc! {
|
||||||
|
"$set": {
|
||||||
|
"_auth._api": api
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match db.find_one(query, None).await? {
|
match db.find_one(query.clone(), None).await? {
|
||||||
Some(_user) => {
|
Some(_user) => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-in request successful");
|
db.update_one(query, update, None).await?;
|
||||||
|
|
||||||
auth.login_user(user_id);
|
|
||||||
auth.remember_user(true);
|
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::OK)
|
.status(StatusCode::OK)
|
||||||
.body(Body::from(format!("{}", user_id)))?)
|
.body(Body::from(api.to_string()))?)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-in request unsuccessful: incorrect credentials");
|
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::UNAUTHORIZED)
|
.status(StatusCode::UNAUTHORIZED)
|
||||||
.body(Body::from("Username or password is incorrect"))?)
|
.body(Body::from("Username or password is incorrect"))?)
|
||||||
|
|
@ -101,24 +86,27 @@ pub async fn post_sign_in(Path(user_id): Path<ObjectId>, auth: AuthenticationSes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post_sign_up(Json(body): Json<User>) -> ApiResult {
|
pub async fn post_sign_up(Json(body): Json<User>) -> ApiResult {
|
||||||
let id = "guest_user";
|
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-up request initiated");
|
|
||||||
|
|
||||||
let db = get_users().await?;
|
let db = get_users().await?;
|
||||||
let query = to_document(&body)?;
|
let auth = body.clone().auth.unwrap_or_default();
|
||||||
|
let query = doc! {
|
||||||
|
"$expr": {
|
||||||
|
"$and": [
|
||||||
|
{ "$eq": ["$username", &body.username] },
|
||||||
|
{ "$eq": ["$_auth._hash", &auth.hash]},
|
||||||
|
{ "$eq": ["$_auth._salt", &auth.salt]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match db.find_one(query.clone(), None).await? {
|
match db.find_one(query, None).await? {
|
||||||
Some(_user) => {
|
Some(_user) => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-up request unsuccessful: username already exists");
|
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::NOT_ACCEPTABLE)
|
.status(StatusCode::NOT_ACCEPTABLE)
|
||||||
.body(Body::from("Username is already taken"))?)
|
.body(Body::from("Username is already taken"))?)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-up request successful");
|
|
||||||
|
|
||||||
db.insert_one(body, None).await?;
|
db.insert_one(body, None).await?;
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::CREATED)
|
.status(StatusCode::CREATED)
|
||||||
.body(Body::from("Account created successfully"))?)
|
.body(Body::from("Account created successfully"))?)
|
||||||
|
|
@ -127,25 +115,30 @@ pub async fn post_sign_up(Json(body): Json<User>) -> ApiResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn post_sign_out(Path(user_id): Path<ObjectId>, auth: AuthenticationSession) -> ApiResult {
|
pub async fn post_sign_out(headers: HeaderMap) -> ApiResult {
|
||||||
let id = format!("user_id: {}", user_id);
|
let db = get_users().await?;
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-out request initiated");
|
let api = headers["api_key"].to_str()?;
|
||||||
|
|
||||||
match auth.is_authenticated() {
|
let query = doc! {
|
||||||
true => {
|
"$expr": { "$eq": ["$_auth._api", ObjectId::parse_str(api)?] }
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-out request successful");
|
};
|
||||||
|
let update = doc! {
|
||||||
|
"$unset": {
|
||||||
|
"_auth._api": ObjectId::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auth.logout_user();
|
match db.find_one(query.clone(), None).await? {
|
||||||
|
Some(_user) => {
|
||||||
|
db.update_one(query, update, None).await?;
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::OK)
|
.status(StatusCode::OK)
|
||||||
.body(Body::from("Sign out successful"))?)
|
.body(Body::from("Sign out successful"))?)
|
||||||
},
|
},
|
||||||
false => {
|
None => {
|
||||||
macro_info_log!(&Utc::now().to_string(), &id, "Sign-out request unsuccessful: user was not logged in");
|
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.status(StatusCode::NOT_ACCEPTABLE)
|
.status(StatusCode::NOT_ACCEPTABLE)
|
||||||
.body(Body::from("No user is not logged in"))?)
|
.body(Body::from("User does not exist"))?)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,8 @@ use mongodb::{
|
||||||
bson::{doc, oid::ObjectId, DateTime},
|
bson::{doc, oid::ObjectId, DateTime},
|
||||||
Client, Collection, Database,
|
Client, Collection, Database,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn get_db_client() -> Result<Client> {
|
pub async fn get_db_client() -> Result<Client> {
|
||||||
Ok(Client::with_uri_str("mongodb://localhost:27017").await?)
|
Ok(Client::with_uri_str("mongodb://root:example@localhost:27017").await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_database() -> Result<Database> {
|
pub async fn get_database() -> Result<Database> {
|
||||||
|
|
@ -100,46 +99,21 @@ impl LogEntry {
|
||||||
pub struct User {
|
pub struct User {
|
||||||
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
|
||||||
pub id: Option<ObjectId>,
|
pub id: Option<ObjectId>,
|
||||||
#[serde(rename="_auth")]
|
#[serde(rename="_auth", skip_serializing_if = "Option::is_none")]
|
||||||
pub auth: Auth,
|
pub auth: Option<Auth>,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
#[serde(skip_serializing)]
|
|
||||||
logged_in: bool,
|
|
||||||
}
|
}
|
||||||
impl User {
|
impl User {
|
||||||
pub fn new(username: String) -> Self {
|
pub fn new(username: String) -> Self {
|
||||||
let id = None;
|
let id = None;
|
||||||
let auth = Default::default();
|
let auth = Default::default();
|
||||||
let logged_in = false;
|
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
auth,
|
auth,
|
||||||
username,
|
username,
|
||||||
logged_in,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[async_trait]
|
|
||||||
impl Authentication<User, ObjectId, Client> for User {
|
|
||||||
async fn load_user(user_id: ObjectId, db: Option<&Client>) -> Result<User> {
|
|
||||||
Ok(db.unwrap()
|
|
||||||
.database("dermy")
|
|
||||||
.collection::<User>("users")
|
|
||||||
.find_one(doc! {"_id": user_id}, None).await?.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_authenticated(&self) -> bool {
|
|
||||||
self.logged_in
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_active(&self) -> bool {
|
|
||||||
self.logged_in
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_anonymous(&self) -> bool {
|
|
||||||
!self.logged_in
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
#[serde(rename = "_hash", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "_hash", skip_serializing_if = "Option::is_none")]
|
||||||
|
|
|
||||||
47
src/lib.rs
47
src/lib.rs
|
|
@ -1,40 +1,21 @@
|
||||||
mod account;
|
mod account;
|
||||||
mod model;
|
mod model;
|
||||||
|
|
||||||
use account::db::{User, get_db_client};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum_session::{SessionConfig, SessionLayer, SessionStore};
|
use axum_session::{SessionConfig, SessionStore};
|
||||||
use axum_session_auth::{AuthConfig, AuthSessionLayer};
|
|
||||||
use axum_session_mongo::SessionMongoPool;
|
use axum_session_mongo::SessionMongoPool;
|
||||||
use chrono::Utc;
|
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use mongodb::{bson::oid::ObjectId, Client};
|
use mongodb::Client;
|
||||||
use rlg::{config::Config, macro_info_log};
|
|
||||||
|
|
||||||
pub async fn run() -> Result<()> {
|
pub async fn run() -> Result<()> {
|
||||||
let id = "server";
|
|
||||||
|
|
||||||
init_logging();
|
|
||||||
macro_info_log!(&Utc::now().to_string(), id, "Server Initializing...");
|
|
||||||
let db = get_db_client().await?;
|
|
||||||
let session_store = session(db.clone()).await?;
|
|
||||||
let auth_config = AuthConfig::<ObjectId>::default();
|
|
||||||
|
|
||||||
macro_info_log!(&Utc::now().to_string(), id, "Routes Initializing...");
|
let app = router();
|
||||||
|
|
||||||
let app = router()
|
|
||||||
.layer(SessionLayer::new(session_store))
|
|
||||||
.layer(AuthSessionLayer::<User, ObjectId, SessionMongoPool, Client>
|
|
||||||
::new(Some(db)).with_config(auth_config)
|
|
||||||
);
|
|
||||||
macro_info_log!(&Utc::now().to_string(), id, "Routes Initialized");
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
|
||||||
|
|
||||||
axum::serve(listener, app).await?;
|
|
||||||
|
|
||||||
macro_info_log!(&Utc::now().to_string(), id, "Server Initialized");
|
|
||||||
|
|
||||||
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
|
||||||
|
axum::serve(listener, app).await.unwrap();
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,14 +25,6 @@ fn router() -> axum::Router {
|
||||||
//.nest("/predict", model::router())
|
//.nest("/predict", model::router())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn session(db: Client) -> Result<SessionStore<SessionMongoPool>> {
|
|
||||||
let session_config = SessionConfig::default()
|
|
||||||
.with_table_name("sessions");
|
|
||||||
|
|
||||||
Ok(SessionStore::<SessionMongoPool>
|
|
||||||
::new(Some(db.clone().into()), session_config).await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AppError(anyhow::Error);
|
struct AppError(anyhow::Error);
|
||||||
|
|
||||||
impl IntoResponse for AppError {
|
impl IntoResponse for AppError {
|
||||||
|
|
@ -72,9 +45,3 @@ where
|
||||||
Self(err.into())
|
Self(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_logging() {
|
|
||||||
std::env::set_var("LOG_FILE_PATH", "$HOME/.dermy/server.log");
|
|
||||||
|
|
||||||
let config = Config::load();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue