feat: Simplify token generation by removing unnecessary permissions parameter from access and refresh token functions
This commit is contained in:
@@ -98,11 +98,9 @@ impl AuthServiceTrait for AuthService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid unnecessary clone of user for caching if not needed
|
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.as_str()).map(str::to_owned).collect();
|
|
||||||
let user_id = user.id.id.to_raw();
|
let user_id = user.id.id.to_raw();
|
||||||
|
|
||||||
let access_token = match encode_access_token(email.to_string(), user_id.clone(), permissions.clone()) {
|
let access_token = match encode_access_token(email.to_string(), user_id.clone()) {
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -116,7 +114,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let refresh_token = match encode_refresh_token(email.to_string(), user_id, permissions) {
|
let refresh_token = match encode_refresh_token(email.to_string(), user_id) {
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -205,8 +203,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
let access_token = match encode_access_token(payload.email.clone(), user.id.id.to_raw()) {
|
||||||
let access_token = match encode_access_token(payload.email.clone(), user.id.id.to_raw(), permissions.clone()) {
|
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -220,8 +217,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
let refresh_token = match encode_refresh_token(payload.email.clone(), user.id.id.to_raw()) {
|
||||||
let refresh_token = match encode_refresh_token(payload.email.clone(), user.id.id.to_raw(), permissions) {
|
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -432,8 +428,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
let access_token = match encode_access_token(user.email.clone(), user.id.id.to_raw()) {
|
||||||
let access_token = match encode_access_token(user.email.clone(), user.id.id.to_raw(), permissions.clone()) {
|
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!("Failed to generate access token for {}: {}", user.email, _e);
|
error!("Failed to generate access token for {}: {}", user.email, _e);
|
||||||
@@ -443,7 +438,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let refresh_token = match encode_refresh_token(user.email.clone(), user.id.id.to_raw(), permissions) {
|
let refresh_token = match encode_refresh_token(user.email.clone(), user.id.id.to_raw()) {
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!("Failed to generate refresh token for {}: {}", user.email, _e);
|
error!("Failed to generate refresh token for {}: {}", user.email, _e);
|
||||||
@@ -477,8 +472,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let user_repo = UsersRepository::new(&state);
|
let user_repo = UsersRepository::new(&state);
|
||||||
if let Ok(user) = user_repo.query_user_by_email(payload.email.clone()).await {
|
if let Ok(user) = user_repo.query_user_by_email(payload.email.clone()).await {
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
let token = match encode_reset_password_token(user.email.clone(), user.id.id.to_raw()) {
|
||||||
let token = match encode_reset_password_token(user.email.clone(), user.id.id.to_raw(), permissions) {
|
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
error!("Failed to generate reset password token for {}: {}", user.email, _e);
|
error!("Failed to generate reset password token for {}: {}", user.email, _e);
|
||||||
|
|||||||
@@ -338,15 +338,13 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
let access_token = encode_access_token(user.email.clone(), user.id.clone())
|
||||||
let access_token = encode_access_token(user.email.clone(), user.id.clone(), permissions.clone())
|
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("Failed to generate access token for {}: {:?}", user.email, e);
|
error!("Failed to generate access token for {}: {:?}", user.email, e);
|
||||||
Error::Auth("Failed to generate access token".to_string())
|
Error::Auth("Failed to generate access token".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
let refresh_token = encode_refresh_token(user.email.clone(), user.id.clone())
|
||||||
let refresh_token = encode_refresh_token(user.email.clone(), user.id.clone(), permissions)
|
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("Failed to generate refresh token for {}: {:?}", user.email, e);
|
error!("Failed to generate refresh token for {}: {:?}", user.email, e);
|
||||||
Error::Auth("Failed to generate refresh token".to_string())
|
Error::Auth("Failed to generate refresh token".to_string())
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use super::PermissionsEnum;
|
use super::PermissionsEnum;
|
||||||
use crate::{AppState, common_response, decode_access_token};
|
use crate::{AppState, common_response, decode_access_token, UsersRepository};
|
||||||
use axum::{
|
use axum::{
|
||||||
http::{HeaderMap, StatusCode},
|
http::{HeaderMap, StatusCode},
|
||||||
response::Response, Extension,
|
response::Response, Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::headers::{authorization::Bearer, Authorization, HeaderMapExt};
|
use axum_extra::headers::{authorization::Bearer, Authorization, HeaderMapExt};
|
||||||
// Removed imphnen_utils::make_thing as it's no longer needed here
|
|
||||||
|
|
||||||
pub async fn permissions_guard(
|
pub async fn permissions_guard(
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
@@ -32,10 +31,23 @@ pub async fn permissions_guard(
|
|||||||
})?
|
})?
|
||||||
.claims;
|
.claims;
|
||||||
|
|
||||||
// Use permissions from JWT for the check
|
// Fetch user from database to get permissions
|
||||||
|
let user_repo = UsersRepository::new(&state);
|
||||||
|
let user = match user_repo.query_user_by_email(claims.sub.clone()).await {
|
||||||
|
Ok(user) => user,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(common_response(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
"User not found",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check permissions from database
|
||||||
|
let user_permissions: Vec<String> = user.role.permissions.iter().map(|p| p.name.clone()).collect();
|
||||||
for required in &required_permissions {
|
for required in &required_permissions {
|
||||||
let required_str = required.to_string();
|
let required_str = required.to_string();
|
||||||
if !claims.permissions.contains(&required_str) {
|
if !user_permissions.contains(&required_str) {
|
||||||
eprintln!(" MISSING REQUIRED PERMISSION: {required_str}");
|
eprintln!(" MISSING REQUIRED PERMISSION: {required_str}");
|
||||||
return Err(common_response(
|
return Err(common_response(
|
||||||
StatusCode::FORBIDDEN,
|
StatusCode::FORBIDDEN,
|
||||||
|
|||||||
@@ -12,19 +12,18 @@ pub struct Claims {
|
|||||||
pub iat: usize,
|
pub iat: usize,
|
||||||
pub sub: String,
|
pub sub: String,
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
pub permissions: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ACCESS_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::new(Header::default);
|
static ACCESS_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::new(Header::default);
|
||||||
static ACCESS_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
static ACCESS_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
||||||
EncodingKey::from_secret(ENV.access_token_secret.as_ref())
|
EncodingKey::from_secret(ENV.access_token_secret.as_ref())
|
||||||
});
|
});
|
||||||
pub fn encode_access_token(sub: String, user_id: String, permissions: Vec<String>) -> Result<String, StatusCode> {
|
pub fn encode_access_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let expire: TimeDelta = Duration::minutes(15);
|
let expire: TimeDelta = Duration::minutes(15);
|
||||||
let exp: usize = (now + expire).timestamp() as usize;
|
let exp: usize = (now + expire).timestamp() as usize;
|
||||||
let iat: usize = now.timestamp() as usize;
|
let iat: usize = now.timestamp() as usize;
|
||||||
let claim = Claims { iat, exp, sub, user_id, permissions };
|
let claim = Claims { iat, exp, sub, user_id };
|
||||||
encode(
|
encode(
|
||||||
&ACCESS_HEADER,
|
&ACCESS_HEADER,
|
||||||
&claim,
|
&claim,
|
||||||
@@ -33,14 +32,14 @@ pub fn encode_access_token(sub: String, user_id: String, permissions: Vec<String
|
|||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode_reset_password_token(sub: String, user_id: String, permissions: Vec<String>) -> Result<String, StatusCode> {
|
pub fn encode_reset_password_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
||||||
let env = &ENV;
|
let env = &ENV;
|
||||||
let secret: String = env.access_token_secret.clone();
|
let secret: String = env.access_token_secret.clone();
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let expire: TimeDelta = Duration::minutes(5);
|
let expire: TimeDelta = Duration::minutes(5);
|
||||||
let exp: usize = (now + expire).timestamp() as usize;
|
let exp: usize = (now + expire).timestamp() as usize;
|
||||||
let iat: usize = now.timestamp() as usize;
|
let iat: usize = now.timestamp() as usize;
|
||||||
let claim = Claims { iat, exp, sub, user_id, permissions };
|
let claim = Claims { iat, exp, sub, user_id };
|
||||||
encode(
|
encode(
|
||||||
&Header::default(),
|
&Header::default(),
|
||||||
&claim,
|
&claim,
|
||||||
@@ -67,12 +66,12 @@ static REFRESH_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::ne
|
|||||||
static REFRESH_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
static REFRESH_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
||||||
EncodingKey::from_secret(ENV.refresh_token_secret.as_ref())
|
EncodingKey::from_secret(ENV.refresh_token_secret.as_ref())
|
||||||
});
|
});
|
||||||
pub fn encode_refresh_token(sub: String, user_id: String, permissions: Vec<String>) -> Result<String, StatusCode> {
|
pub fn encode_refresh_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let expire: TimeDelta = Duration::days(1);
|
let expire: TimeDelta = Duration::days(1);
|
||||||
let exp: usize = (now + expire).timestamp() as usize;
|
let exp: usize = (now + expire).timestamp() as usize;
|
||||||
let iat: usize = now.timestamp() as usize;
|
let iat: usize = now.timestamp() as usize;
|
||||||
let claim = Claims { iat, exp, sub, user_id, permissions };
|
let claim = Claims { iat, exp, sub, user_id };
|
||||||
encode(
|
encode(
|
||||||
&REFRESH_HEADER,
|
&REFRESH_HEADER,
|
||||||
&claim,
|
&claim,
|
||||||
@@ -95,6 +94,6 @@ pub fn decode_refresh_token(
|
|||||||
result // Explicitly return result
|
result // Explicitly return result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_jwt(user_id: &str, permissions: Vec<String>) -> Result<String, StatusCode> {
|
pub fn generate_jwt(user_id: &str) -> Result<String, StatusCode> {
|
||||||
encode_access_token(user_id.to_string(), user_id.to_string(), permissions)
|
encode_access_token(user_id.to_string(), user_id.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user