feat: auth
This commit is contained in:
+6
-15
@@ -1,31 +1,22 @@
|
||||
use crate::{redisdb_init, Env, RedisClient};
|
||||
use crate::{surrealdb_init, SurrealClient};
|
||||
use axum::{serve, Router};
|
||||
use std::env;
|
||||
use std::{future::Future, net::SocketAddr};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
use crate::{redisdb_init, RedisClient};
|
||||
use crate::{surrealdb_init, SurrealClient};
|
||||
|
||||
pub async fn axum_init<F, Fut>(router_fn: F)
|
||||
where
|
||||
F: FnOnce(SurrealClient, RedisClient) -> Fut,
|
||||
Fut: Future<Output = Router>,
|
||||
{
|
||||
let env = Env::new();
|
||||
let surrealdb = surrealdb_init().await.expect("Failed surrealdb");
|
||||
let redisdb = redisdb_init().await.expect("Failed redisdb");
|
||||
let redisdb = redisdb_init().await.expect("Failed redisdb");
|
||||
let router = router_fn(surrealdb, redisdb).await;
|
||||
|
||||
let addr = SocketAddr::from((
|
||||
[0, 0, 0, 0],
|
||||
env::var("PORT")
|
||||
.unwrap_or_else(|_| "3000".to_string())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
let port = env.port;
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
||||
let listener = TcpListener::bind(&addr).await.unwrap();
|
||||
println!("Listening on http://{}", addr);
|
||||
|
||||
match serve(listener, router).await {
|
||||
Ok(_) => println!("Server stopped gracefully."),
|
||||
Err(err) => println!("Server encountered an error: {}", err),
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use std::env;
|
||||
|
||||
pub struct Env {
|
||||
pub port: u16,
|
||||
pub access_token_secret: String,
|
||||
pub refresh_token_secret: String,
|
||||
pub database_url: String,
|
||||
pub database_schema: String,
|
||||
pub smtp_email: String,
|
||||
pub smtp_password: String,
|
||||
pub smtp_name: String,
|
||||
pub smpt_host: String,
|
||||
pub redis_hostname: String,
|
||||
pub fe_url: String,
|
||||
pub rust_env: String,
|
||||
pub minio_endpoint: String,
|
||||
pub minio_bucket_name: String,
|
||||
pub minio_access_key: String,
|
||||
pub minio_secret_key: String,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
port: env::var("PORT")
|
||||
.unwrap_or("3000".to_string())
|
||||
.parse()
|
||||
.unwrap_or(3000),
|
||||
access_token_secret: env::var("ACCESS_TOKEN_SECRET")
|
||||
.unwrap_or("default_access_secret".to_string()),
|
||||
refresh_token_secret: env::var("REFRESH_TOKEN_SECRET")
|
||||
.unwrap_or("default_refresh_secret".to_string()),
|
||||
database_url: env::var("DATABASE_URL")
|
||||
.unwrap_or("postgres://localhost".to_string()),
|
||||
database_schema: env::var("DATABASE_SCHEMA")
|
||||
.unwrap_or("public".to_string()),
|
||||
smtp_email: env::var("SMTP_EMAIL")
|
||||
.unwrap_or("no-reply@example.com".to_string()),
|
||||
smtp_password: env::var("SMTP_PASSWORD")
|
||||
.unwrap_or("default_smtp_password".to_string()),
|
||||
smtp_name: env::var("SMTP_NAME").unwrap_or("MyApp SMTP".to_string()),
|
||||
smpt_host: env::var("SMPT_HOST").unwrap_or("smpt.gmail.com".to_string()),
|
||||
redis_hostname: env::var("REDIS_HOSTNAME")
|
||||
.unwrap_or("localhost".to_string()),
|
||||
fe_url: env::var("FE_URL").unwrap_or("http://localhost".to_string()),
|
||||
rust_env: env::var("RUST_ENV").unwrap_or("development".to_string()),
|
||||
minio_endpoint: env::var("MINIO_ENDPOINT")
|
||||
.unwrap_or("http://localhost:9000".to_string()),
|
||||
minio_bucket_name: env::var("MINIO_BUCKET_NAME")
|
||||
.unwrap_or("default_bucket".to_string()),
|
||||
minio_access_key: env::var("MINIO_ACCESS_KEY")
|
||||
.unwrap_or("minio_access".to_string()),
|
||||
minio_secret_key: env::var("MINIO_SECRET_KEY")
|
||||
.unwrap_or("minio_secret".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,32 @@
|
||||
use super::Env;
|
||||
use axum::http::StatusCode;
|
||||
use chrono::{Duration, TimeDelta, Utc};
|
||||
use jsonwebtoken::{
|
||||
decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TokenSub {
|
||||
pub email: String,
|
||||
pub role_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Claims {
|
||||
pub exp: usize,
|
||||
pub iat: usize,
|
||||
pub email: String,
|
||||
pub sub: TokenSub,
|
||||
}
|
||||
|
||||
pub fn encode_access_token(email: &str) -> Result<String, StatusCode> {
|
||||
let secret: String = env::var("ACCESS_TOKEN_SECRET")
|
||||
.unwrap_or("this-is-secret".to_string())
|
||||
.to_string();
|
||||
pub fn encode_access_token(sub: TokenSub) -> Result<String, StatusCode> {
|
||||
let env = Env::new();
|
||||
let secret: String = env.access_token_secret;
|
||||
let now = Utc::now();
|
||||
let expire: TimeDelta = Duration::minutes(15);
|
||||
let exp: usize = (now + expire).timestamp() as usize;
|
||||
let iat: usize = now.timestamp() as usize;
|
||||
let claim = Claims {
|
||||
iat,
|
||||
exp,
|
||||
email: email.to_string(),
|
||||
};
|
||||
let claim = Claims { iat, exp, sub };
|
||||
encode(
|
||||
&Header::default(),
|
||||
&claim,
|
||||
@@ -37,9 +38,8 @@ pub fn encode_access_token(email: &str) -> Result<String, StatusCode> {
|
||||
pub fn decode_access_token(
|
||||
jwt_token: &str,
|
||||
) -> Result<TokenData<Claims>, StatusCode> {
|
||||
let secret = env::var("ACCESS_TOKEN_SECRET")
|
||||
.unwrap_or("this-is-secret".to_string())
|
||||
.to_string();
|
||||
let env = Env::new();
|
||||
let secret: String = env.access_token_secret;
|
||||
let result: Result<TokenData<Claims>, StatusCode> = decode(
|
||||
&jwt_token,
|
||||
&DecodingKey::from_secret(secret.as_ref()),
|
||||
@@ -49,19 +49,14 @@ pub fn decode_access_token(
|
||||
result
|
||||
}
|
||||
|
||||
pub fn encode_refresh_token(email: &str) -> Result<String, StatusCode> {
|
||||
let secret: String = env::var("REFRESH_TOKEN_SECRET")
|
||||
.unwrap_or("this-is-secret".to_string())
|
||||
.to_string();
|
||||
pub fn encode_refresh_token(sub: TokenSub) -> Result<String, StatusCode> {
|
||||
let env = Env::new();
|
||||
let secret: String = env.refresh_token_secret;
|
||||
let now = Utc::now();
|
||||
let expire: TimeDelta = Duration::days(1);
|
||||
let exp: usize = (now + expire).timestamp() as usize;
|
||||
let iat: usize = now.timestamp() as usize;
|
||||
let claim = Claims {
|
||||
iat,
|
||||
exp,
|
||||
email: email.to_string(),
|
||||
};
|
||||
let claim = Claims { iat, exp, sub };
|
||||
encode(
|
||||
&Header::default(),
|
||||
&claim,
|
||||
@@ -73,9 +68,8 @@ pub fn encode_refresh_token(email: &str) -> Result<String, StatusCode> {
|
||||
pub fn decode_refresh_token(
|
||||
jwt_token: &str,
|
||||
) -> Result<TokenData<Claims>, StatusCode> {
|
||||
let secret = env::var("REFRESH_TOKEN_SECRET")
|
||||
.unwrap_or("this-is-secret".to_string())
|
||||
.to_string();
|
||||
let env = Env::new();
|
||||
let secret: String = env.refresh_token_secret;
|
||||
let result: Result<TokenData<Claims>, StatusCode> = decode(
|
||||
&jwt_token,
|
||||
&DecodingKey::from_secret(secret.as_ref()),
|
||||
|
||||
+9
-10
@@ -1,18 +1,20 @@
|
||||
use super::Env;
|
||||
use lettre::message::Mailbox;
|
||||
use lettre::transport::smtp::authentication::Credentials;
|
||||
use lettre::{Message, SmtpTransport, Transport};
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
|
||||
pub fn send_email(
|
||||
to: &str,
|
||||
subject: &str,
|
||||
body: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let sender_email = env::var("SMTP_EMAIL")?.to_string();
|
||||
let sender_name = env::var("SMTP_NAME")?.to_string();
|
||||
let sender_password = env::var("SMTP_PASSWORD")?.to_string();
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let env = Env::new();
|
||||
let host = env.smpt_host;
|
||||
let sender_email = env.smtp_email;
|
||||
let sender_name = env.smtp_name;
|
||||
let sender_password = env.smtp_password;
|
||||
let recipient_email = to;
|
||||
|
||||
let email = Message::builder()
|
||||
.from(Mailbox::new(
|
||||
Some(sender_name.replace("-", " ")),
|
||||
@@ -21,14 +23,11 @@ pub fn send_email(
|
||||
.to(recipient_email.parse()?)
|
||||
.subject(subject)
|
||||
.body(body.to_string())?;
|
||||
|
||||
let smtp_credentials =
|
||||
Credentials::new(sender_email, sender_password.replace("-", " "));
|
||||
|
||||
let mailer = SmtpTransport::relay("smtp.gmail.com")?
|
||||
let mailer = SmtpTransport::relay(&host)?
|
||||
.credentials(smtp_credentials)
|
||||
.build();
|
||||
|
||||
match mailer.send(&email) {
|
||||
Ok(_) => {
|
||||
println!("Email sent successfully to {}", to);
|
||||
|
||||
+4
-2
@@ -1,13 +1,15 @@
|
||||
pub mod argon;
|
||||
pub mod axum;
|
||||
pub mod enviroment;
|
||||
pub mod jsonwebtoken;
|
||||
pub mod lettre;
|
||||
pub mod redis;
|
||||
pub mod redisdb;
|
||||
pub mod surrealdb;
|
||||
|
||||
pub use argon::*;
|
||||
pub use axum::*;
|
||||
pub use enviroment::*;
|
||||
pub use jsonwebtoken::*;
|
||||
pub use lettre::*;
|
||||
pub use redis::*;
|
||||
pub use redisdb::*;
|
||||
pub use surrealdb::*;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
use redis::Client;
|
||||
use redis::RedisResult;
|
||||
use std::env;
|
||||
|
||||
pub async fn redisdb_init() -> RedisResult<Client> {
|
||||
let host_name =
|
||||
env::var("REDIS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string());
|
||||
let uri_scheme = if env::var("IS_TLS").is_ok() {
|
||||
"rediss"
|
||||
} else {
|
||||
"redis"
|
||||
};
|
||||
let url = format!("{}://{}", uri_scheme, host_name);
|
||||
let client = Client::open(url)?;
|
||||
Ok(client)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
use super::Env;
|
||||
use redis::Client;
|
||||
use redis::RedisResult;
|
||||
|
||||
pub async fn redisdb_init() -> RedisResult<Client> {
|
||||
let env = Env::new();
|
||||
let host_name = env.redis_hostname;
|
||||
let url = format!("redis://{}", host_name);
|
||||
let client = Client::open(url)?;
|
||||
Ok(client)
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
use surrealdb::engine::remote::ws::{Client, Ws};
|
||||
use surrealdb::{Result, Surreal};
|
||||
|
||||
use crate::SurrealClient;
|
||||
use surrealdb::engine::remote::http::{Client, Http};
|
||||
use surrealdb::{Result, Surreal};
|
||||
|
||||
pub async fn surrealdb_init() -> Result<SurrealClient> {
|
||||
let db = Surreal::<Client>::init();
|
||||
db.connect::<Ws>("ws://localhost:8000").await?;
|
||||
db.connect::<Http>("localhost:8000").await?;
|
||||
db.signin(surrealdb::opt::auth::Root {
|
||||
username: "root",
|
||||
password: "root",
|
||||
})
|
||||
.await?;
|
||||
db.use_ns("test").use_db("test").await?;
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user