feat: ✨ refresh token system
This commit is contained in:
parent
87412ca828
commit
cf1107d09c
7 changed files with 85 additions and 63 deletions
|
@ -10,8 +10,8 @@ pub async fn create(
|
|||
sqlx::query_as!(
|
||||
Login,
|
||||
r#"
|
||||
INSERT INTO "login"(user_id, token)
|
||||
VALUES ($1, $2)
|
||||
INSERT INTO "login"(user_id, token)
|
||||
VALUES ($1, $2)
|
||||
RETURNING *
|
||||
"#,
|
||||
user_id,
|
||||
|
@ -38,24 +38,6 @@ pub async fn read(
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
user_id: &i64,
|
||||
token: &String,
|
||||
database_connection: &Pool<Postgres>,
|
||||
) -> Result<Login, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Login,
|
||||
r#"
|
||||
UPDATE "login" SET "token" = $2 WHERE "user_id" = $1
|
||||
RETURNING *
|
||||
"#,
|
||||
user_id,
|
||||
token,
|
||||
)
|
||||
.fetch_one(database_connection)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete(
|
||||
user_id: &i64,
|
||||
token: &String,
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use jwt_simple::{
|
||||
claims::Claims,
|
||||
common::VerificationOptions,
|
||||
|
@ -8,10 +11,54 @@ use sqlx::{Pool, Postgres};
|
|||
|
||||
use crate::{database::login, SERVER_CONFIG};
|
||||
|
||||
static TOKEN_META: LazyLock<TokenMeta> = LazyLock::new(TokenMeta::init);
|
||||
|
||||
struct TokenMeta {
|
||||
token_key: HS256Key,
|
||||
token_verification_options: Option<VerificationOptions>,
|
||||
}
|
||||
|
||||
impl TokenMeta {
|
||||
fn init() -> Self {
|
||||
Self {
|
||||
token_key: HS256Key::generate(),
|
||||
token_verification_options: {
|
||||
let mut verification_options = VerificationOptions::default();
|
||||
verification_options.time_tolerance = Some(jwt_simple::prelude::Duration::from(0));
|
||||
Some(verification_options)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_token() -> Option<String> {
|
||||
let key = &TOKEN_META.token_key;
|
||||
let claims = Claims::create(jwt_simple::prelude::Duration::from_mins(
|
||||
SERVER_CONFIG.login_token_expiration_time_limit as u64,
|
||||
));
|
||||
let token = key.authenticate(claims).unwrap();
|
||||
match TokenMeta::verify_token(&token).await {
|
||||
true => Some(token),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn verify_token(token: &String) -> bool {
|
||||
let token_meta = &TOKEN_META;
|
||||
token_meta
|
||||
.token_key
|
||||
.verify_token::<jwt_simple::prelude::NoCustomClaims>(
|
||||
token,
|
||||
token_meta.token_verification_options.clone(),
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Login {
|
||||
pub user_id: i64,
|
||||
pub token: String,
|
||||
pub token_creation_time: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Login {
|
||||
|
@ -19,15 +66,9 @@ impl Login {
|
|||
user_id: &i64,
|
||||
database_connection: &Pool<Postgres>,
|
||||
) -> Result<Login, sqlx::Error> {
|
||||
let key = HS256Key::generate();
|
||||
let claims = Claims::create(jwt_simple::prelude::Duration::from_mins(
|
||||
SERVER_CONFIG.login_token_time_limit as u64,
|
||||
));
|
||||
let mut verification_options = VerificationOptions::default();
|
||||
verification_options.time_tolerance = Some(jwt_simple::prelude::Duration::from(0));
|
||||
|
||||
let token = key.authenticate(claims).unwrap();
|
||||
|
||||
let token = TokenMeta::create_token()
|
||||
.await
|
||||
.expect("Should not panic if it isn't configured wrong");
|
||||
login::create(user_id, &token, database_connection).await
|
||||
}
|
||||
|
||||
|
@ -44,7 +85,23 @@ impl Login {
|
|||
token: &String,
|
||||
database_connection: &Pool<Postgres>,
|
||||
) -> Result<Login, sqlx::Error> {
|
||||
login::update(user_id, token, database_connection).await
|
||||
let login = Login::read(user_id, token, database_connection).await?;
|
||||
|
||||
match TokenMeta::verify_token(token).await {
|
||||
true => Ok(login),
|
||||
false => {
|
||||
if DateTime::<Utc>::default()
|
||||
.signed_duration_since(&login.token_creation_time)
|
||||
.num_minutes()
|
||||
<= SERVER_CONFIG.login_token_refresh_time_limit as i64
|
||||
{
|
||||
Login::delete(user_id, token, database_connection).await?;
|
||||
Login::create(user_id, database_connection).await
|
||||
} else {
|
||||
Ok(login)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub async fn delete(
|
||||
user_id: &i64,
|
||||
|
|
|
@ -52,7 +52,8 @@ impl Default for DatabaseConfig {
|
|||
pub struct ServerConfig {
|
||||
pub address: String,
|
||||
pub otp_time_limit: usize,
|
||||
pub login_token_time_limit: usize,
|
||||
pub login_token_expiration_time_limit: usize,
|
||||
pub login_token_refresh_time_limit: usize,
|
||||
pub concurrency_limit: usize,
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,10 @@ impl Default for ServerConfig {
|
|||
Self {
|
||||
address: server_configs.pop_front().unwrap().parse().unwrap(),
|
||||
otp_time_limit: value_or_max(server_configs.pop_front().unwrap()),
|
||||
login_token_time_limit: value_or_max(server_configs.pop_front().unwrap()),
|
||||
login_token_expiration_time_limit: value_or_max(
|
||||
server_configs.pop_front().unwrap(),
|
||||
),
|
||||
login_token_refresh_time_limit: value_or_max(server_configs.pop_front().unwrap()),
|
||||
concurrency_limit: value_or_max(server_configs.pop_front().unwrap()),
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue