Added auth
This commit is contained in:
62
src/auth.rs
Normal file
62
src/auth.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use actix_session::Session;
|
||||
use argon2::{
|
||||
Argon2,
|
||||
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng},
|
||||
};
|
||||
|
||||
use crate::error::ApiError;
|
||||
|
||||
/// Hash a password using Argon2id.
|
||||
pub fn hash_password(password: &str) -> Result<String, ApiError> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
argon2
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.map(|h| h.to_string())
|
||||
.map_err(|e| ApiError::Internal(format!("failed to hash password: {e}")))
|
||||
}
|
||||
|
||||
/// Verify a password against a stored hash.
|
||||
pub fn verify_password(password: &str, hash: &str) -> bool {
|
||||
let Ok(parsed) = PasswordHash::new(hash) else {
|
||||
return false;
|
||||
};
|
||||
Argon2::default()
|
||||
.verify_password(password.as_bytes(), &parsed)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
/// Session keys.
|
||||
const SESSION_USER_ID: &str = "user_id";
|
||||
const SESSION_USERNAME: &str = "username";
|
||||
const SESSION_ROLE: &str = "role";
|
||||
|
||||
/// Store user info in the session.
|
||||
pub fn set_session(session: &Session, user_id: i32, username: &str, role: &str) {
|
||||
let _ = session.insert(SESSION_USER_ID, user_id);
|
||||
let _ = session.insert(SESSION_USERNAME, username.to_string());
|
||||
let _ = session.insert(SESSION_ROLE, role.to_string());
|
||||
}
|
||||
|
||||
/// Extract user info from session. Returns (user_id, username, role).
|
||||
pub fn get_session_user(session: &Session) -> Option<(i32, String, String)> {
|
||||
let user_id = session.get::<i32>(SESSION_USER_ID).ok()??;
|
||||
let username = session.get::<String>(SESSION_USERNAME).ok()??;
|
||||
let role = session.get::<String>(SESSION_ROLE).ok()??;
|
||||
Some((user_id, username, role))
|
||||
}
|
||||
|
||||
/// Require authentication. Returns (user_id, username, role) or 401.
|
||||
pub fn require_auth(session: &Session) -> Result<(i32, String, String), ApiError> {
|
||||
get_session_user(session)
|
||||
.ok_or_else(|| ApiError::Unauthorized("not logged in".into()))
|
||||
}
|
||||
|
||||
/// Require admin role. Returns (user_id, username, role) or 403.
|
||||
pub fn require_admin(session: &Session) -> Result<(i32, String, String), ApiError> {
|
||||
let user = require_auth(session)?;
|
||||
if user.2 != "admin" {
|
||||
return Err(ApiError::Forbidden("admin access required".into()));
|
||||
}
|
||||
Ok(user)
|
||||
}
|
||||
Reference in New Issue
Block a user