**JWT Encoding and Decoding**
use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation, Algorithm};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
exp: usize,
iat: usize,
iss: String,
}
pub struct JwtService {
encoding_key: EncodingKey,
decoding_key: DecodingKey,
validation: Validation,
}
impl JwtService {
pub fn new(secret: &[u8], issuer: &str) -> Self {
let mut validation = Validation::new(Algorithm::HS256);
validation.set_issuer(&[issuer]);
validation.leeway = 60;
Self {
encoding_key: EncodingKey::from_secret(secret),
decoding_key: DecodingKey::from_secret(secret),
validation,
}
}
pub fn create_token(&self, claims: &Claims) -> Result<String, AuthError> {
encode(&Header::default(), claims, &self.encoding_key)
.map_err(|_| AuthError::TokenCreation)
}
pub fn validate_token(&self, token: &str) -> Result<Claims, AuthError> {
decode::<Claims>(token, &self.decoding_key, &self.validation)
.map(|data| data.claims)
.map_err(|err| match *err.kind() {
ErrorKind::ExpiredSignature => AuthError::TokenExpired,
_ => AuthError::InvalidToken,
})
}
}
**Argon2 Password Hashing**
use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
fn hash_password(password: &str) -> Result<String, argon2::password_hash::Error> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
Ok(argon2.hash_password(password.as_bytes(), &salt)?.to_string())
}
fn verify_password(password: &str, hash: &str) -> bool {
let parsed_hash = match PasswordHash::new(hash) {
Ok(h) => h,
Err(_) => return false,
};
Argon2::default().verify_password(password.as_bytes(), &parsed_hash).is_ok()
}