use crate::*;
impl JwtConfig {
pub fn new<S>(secret: S, expiration_seconds: u64, issuer: S) -> Self
where
S: AsRef<str>,
{
Self {
secret: secret.as_ref().to_string(),
expiration_seconds,
issuer: issuer.as_ref().to_string(),
}
}
pub fn get_secret(&self) -> &String {
&self.secret
}
pub fn set_secret<S>(&mut self, secret: S) -> &mut Self
where
S: AsRef<str>,
{
self.secret = secret.as_ref().to_string();
self
}
pub fn get_expiration_seconds(&self) -> u64 {
self.expiration_seconds
}
pub fn set_expiration_seconds(&mut self, expiration_seconds: u64) -> &mut Self {
self.expiration_seconds = expiration_seconds;
self
}
pub fn get_issuer(&self) -> &String {
&self.issuer
}
pub fn set_issuer<S>(&mut self, issuer: S) -> &mut Self
where
S: AsRef<str>,
{
self.issuer = issuer.as_ref().to_string();
self
}
}
impl JwtExtraJwtClaims {
pub fn new<S>(sub: S, iss: S, exp: usize, iat: usize, nbf: usize) -> Self
where
S: AsRef<str>,
{
Self {
sub: sub.as_ref().to_string(),
iss: iss.as_ref().to_string(),
exp,
iat,
nbf,
}
}
pub fn get_sub(&self) -> &String {
&self.sub
}
pub fn set_sub<S>(&mut self, sub: S) -> &mut Self
where
S: AsRef<str>,
{
self.sub = sub.as_ref().to_string();
self
}
pub fn get_iss(&self) -> &String {
&self.iss
}
pub fn set_iss<S>(&mut self, iss: S) -> &mut Self
where
S: AsRef<str>,
{
self.iss = iss.as_ref().to_string();
self
}
pub fn get_exp(&self) -> usize {
self.exp
}
pub fn set_exp(&mut self, exp: usize) -> &mut Self {
self.exp = exp;
self
}
pub fn get_iat(&self) -> usize {
self.iat
}
pub fn set_iat(&mut self, iat: usize) -> &mut Self {
self.iat = iat;
self
}
pub fn get_nbf(&self) -> usize {
self.nbf
}
pub fn set_nbf(&mut self, nbf: usize) -> &mut Self {
self.nbf = nbf;
self
}
}
impl JwtToken {
pub fn get_token(&self) -> &String {
&self.token
}
pub fn set_token<S>(&mut self, token: S) -> &mut Self
where
S: AsRef<str>,
{
self.token = token.as_ref().to_string();
self
}
pub fn get_token_type(&self) -> &String {
&self.token_type
}
pub fn set_token_type<S>(&mut self, token_type: S) -> &mut Self
where
S: AsRef<str>,
{
self.token_type = token_type.as_ref().to_string();
self
}
pub fn get_expires_in(&self) -> u64 {
self.expires_in
}
pub fn set_expires_in(&mut self, expires_in: u64) -> &mut Self {
self.expires_in = expires_in;
self
}
}
impl JwtService {
pub fn new(
config: JwtConfig,
encoding_key: EncodingKey,
decoding_key: DecodingKey,
validation: Validation,
) -> Self {
Self {
config,
encoding_key,
decoding_key,
validation,
}
}
pub fn get_config(&self) -> &JwtConfig {
&self.config
}
pub fn get_encoding_key(&self) -> &EncodingKey {
&self.encoding_key
}
pub fn get_decoding_key(&self) -> &DecodingKey {
&self.decoding_key
}
pub fn get_validation(&self) -> &Validation {
&self.validation
}
}
impl<T: Default> CustomExtraJwtClaims<T> {
pub fn get_custom(&self) -> &T {
&self.custom
}
pub fn set_custom(&mut self, custom: T) -> &mut Self {
self.custom = custom;
self
}
pub fn get_sub(&self) -> &String {
&self.sub
}
pub fn set_sub<S>(&mut self, sub: S) -> &mut Self
where
S: AsRef<str>,
{
self.sub = sub.as_ref().to_string();
self
}
pub fn get_iss(&self) -> &String {
&self.iss
}
pub fn set_iss<S>(&mut self, iss: S) -> &mut Self
where
S: AsRef<str>,
{
self.iss = iss.as_ref().to_string();
self
}
pub fn get_exp(&self) -> usize {
self.exp
}
pub fn set_exp(&mut self, exp: usize) -> &mut Self {
self.exp = exp;
self
}
pub fn get_iat(&self) -> usize {
self.iat
}
pub fn set_iat(&mut self, iat: usize) -> &mut Self {
self.iat = iat;
self
}
}
impl ExtraJwtClaims {
pub fn new<S>(sub: S, iss: S, exp: usize) -> Self
where
S: AsRef<str>,
{
let now: usize = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as usize;
Self {
sub: sub.as_ref().to_string(),
iss: iss.as_ref().to_string(),
exp,
iat: now,
extra: HashMap::new(),
}
}
pub fn get_sub(&self) -> &String {
&self.sub
}
pub fn set_sub<S>(&mut self, sub: S) -> &mut Self
where
S: AsRef<str>,
{
self.sub = sub.as_ref().to_string();
self
}
pub fn get_iss(&self) -> &String {
&self.iss
}
pub fn set_iss<S>(&mut self, iss: S) -> &mut Self
where
S: AsRef<str>,
{
self.iss = iss.as_ref().to_string();
self
}
pub fn get_exp(&self) -> usize {
self.exp
}
pub fn set_exp(&mut self, exp: usize) -> &mut Self {
self.exp = exp;
self
}
pub fn get_iat(&self) -> usize {
self.iat
}
pub fn set_iat(&mut self, iat: usize) -> &mut Self {
self.iat = iat;
self
}
pub fn get_extra(&self) -> &HashMap<String, Value> {
&self.extra
}
pub fn get_mut_extra(&mut self) -> &mut HashMap<String, Value> {
&mut self.extra
}
pub fn set_extra(&mut self, extra: HashMap<String, Value>) -> &mut Self {
self.extra = extra;
self
}
}
impl std::fmt::Display for JwtValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Expired => write!(f, "Token has expired"),
Self::InvalidSignature => write!(f, "Invalid token signature"),
Self::InvalidIssuer => write!(f, "Invalid token issuer"),
Self::InvalidSubject => write!(f, "Invalid token subject"),
Self::NotYetValid => write!(f, "Token is not yet valid"),
Self::Malformed => write!(f, "Malformed token"),
Self::Other(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for JwtValidationError {}
impl From<jsonwebtoken::errors::Error> for JwtValidationError {
fn from(error: jsonwebtoken::errors::Error) -> Self {
match error.kind() {
jsonwebtoken::errors::ErrorKind::ExpiredSignature => Self::Expired,
jsonwebtoken::errors::ErrorKind::InvalidSignature => Self::InvalidSignature,
jsonwebtoken::errors::ErrorKind::InvalidIssuer => Self::InvalidIssuer,
jsonwebtoken::errors::ErrorKind::InvalidSubject => Self::InvalidSubject,
jsonwebtoken::errors::ErrorKind::ImmatureSignature => Self::NotYetValid,
_ => Self::Other(error.to_string()),
}
}
}
impl JwtConfig {
pub fn with_settings(secret: String, expiration_seconds: u64, issuer: String) -> Self {
let mut instance: JwtConfig = Self::default();
instance
.set_secret(secret)
.set_expiration_seconds(expiration_seconds)
.set_issuer(issuer);
instance
}
}
impl From<JwtConfig> for JwtService {
fn from(config: JwtConfig) -> Self {
let encoding_key: EncodingKey = EncodingKey::from_secret(config.get_secret().as_bytes());
let decoding_key: DecodingKey = DecodingKey::from_secret(config.get_secret().as_bytes());
let mut validation: Validation = Validation::new(Algorithm::HS256);
validation.set_issuer(&[config.get_issuer()]);
Self::new(config, encoding_key, decoding_key, validation)
}
}
impl JwtService {
pub fn generate_token<S>(&self, subject: S) -> Result<JwtToken, String>
where
S: AsRef<str>,
{
let now: usize = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as usize;
let exp: usize = now + self.get_config().get_expiration_seconds() as usize;
let claims: JwtExtraJwtClaims = JwtExtraJwtClaims::new(
subject.as_ref().to_string(),
self.get_config().get_issuer().clone(),
exp,
now,
now,
);
let token: String = encode(
&Header::new(Algorithm::HS256),
&claims,
self.get_encoding_key(),
)
.map_err(|error| error.to_string())?;
let mut jwt_token: JwtToken = JwtToken::default();
jwt_token
.set_token(token)
.set_token_type(BEARER)
.set_expires_in(self.get_config().get_expiration_seconds());
Ok(jwt_token)
}
pub fn validate_token<T>(&self, token: T) -> Result<JwtExtraJwtClaims, JwtValidationError>
where
T: AsRef<str>,
{
let token_data = decode::<JwtExtraJwtClaims>(
token.as_ref(),
self.get_decoding_key(),
self.get_validation(),
)?;
Ok(token_data.claims)
}
pub fn get_subject_from_token<T>(&self, token: T) -> Result<String, String>
where
T: AsRef<str>,
{
let claims: JwtExtraJwtClaims = self.validate_token(token).map_err(|e| e.to_string())?;
Ok(claims.get_sub().clone())
}
pub fn is_token_expired<T>(&self, token: T) -> Result<bool, String>
where
T: AsRef<str>,
{
match decode::<JwtExtraJwtClaims>(
token.as_ref(),
self.get_decoding_key(),
&Validation::new(Algorithm::HS256),
) {
Ok(token_data) => {
let now: usize = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as usize;
Ok(token_data.claims.get_exp() < now)
}
Err(error) => Err(error.to_string()),
}
}
}
impl JwtService {
pub fn generate_token_with_claims<U, S>(
&self,
subject: S,
claims: U,
) -> Result<JwtToken, String>
where
U: Clone + Default + Serialize + for<'de> Deserialize<'de>,
S: AsRef<str>,
{
let now: usize = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as usize;
let mut res_claims: CustomExtraJwtClaims<U> = CustomExtraJwtClaims::default();
res_claims
.set_custom(claims)
.set_sub(subject.as_ref())
.set_iss(self.get_config().get_issuer().clone())
.set_exp(now + self.get_config().get_expiration_seconds() as usize)
.set_iat(now);
let token: String = encode(
&Header::new(Algorithm::HS256),
&res_claims,
self.get_encoding_key(),
)
.map_err(|error| error.to_string())?;
let mut jwt_token: JwtToken = JwtToken::default();
jwt_token.set_token(token);
jwt_token.set_token_type(BEARER);
jwt_token.set_expires_in(self.get_config().get_expiration_seconds());
Ok(jwt_token)
}
pub fn validate_token_with_claims<U, T>(
&self,
token: T,
) -> Result<CustomExtraJwtClaims<U>, JwtValidationError>
where
U: Clone + Default + Serialize + for<'de> Deserialize<'de>,
T: AsRef<str>,
{
let token_data: TokenData<CustomExtraJwtClaims<U>> = decode::<CustomExtraJwtClaims<U>>(
token.as_ref(),
self.get_decoding_key(),
self.get_validation(),
)?;
Ok(token_data.claims)
}
pub fn generate_token_with_extra_claims<S>(
&self,
subject: S,
extra: HashMap<String, Value>,
) -> Result<JwtToken, String>
where
S: AsRef<str>,
{
let now: usize = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as usize;
let mut claims: ExtraJwtClaims = ExtraJwtClaims::new(
subject.as_ref().to_string(),
self.get_config().get_issuer().clone(),
now + self.get_config().get_expiration_seconds() as usize,
);
claims.set_extra(extra);
let token: String = encode(
&Header::new(Algorithm::HS256),
&claims,
self.get_encoding_key(),
)
.map_err(|error| error.to_string())?;
let mut jwt_token: JwtToken = JwtToken::default();
jwt_token.set_token(token);
jwt_token.set_token_type(BEARER);
jwt_token.set_expires_in(self.get_config().get_expiration_seconds());
Ok(jwt_token)
}
pub fn validate_token_with_extra_claims<T>(
&self,
token: T,
) -> Result<ExtraJwtClaims, JwtValidationError>
where
T: AsRef<str>,
{
let token_data: TokenData<ExtraJwtClaims> = decode::<ExtraJwtClaims>(
token.as_ref(),
self.get_decoding_key(),
self.get_validation(),
)?;
Ok(token_data.claims)
}
pub fn get_from_token<T, K>(
&self,
token: T,
field_key: K,
) -> Result<Option<Value>, JwtValidationError>
where
T: AsRef<str>,
K: AsRef<str>,
{
let claims: ExtraJwtClaims = self.validate_token_with_extra_claims(token)?;
Ok(claims.get(field_key.as_ref()).cloned())
}
}
impl ExtraJwtClaims {
pub fn insert(mut self, key: String, value: Value) -> Self {
self.get_mut_extra().insert(key, value);
self
}
pub fn extend_extra(mut self, extra: HashMap<String, Value>) -> Self {
self.get_mut_extra().extend(extra);
self
}
pub fn get<K>(&self, key: K) -> Option<&Value>
where
K: AsRef<str>,
{
self.get_extra().get(key.as_ref())
}
pub fn contains_key<K>(&self, key: K) -> bool
where
K: AsRef<str>,
{
self.get_extra().contains_key(key.as_ref())
}
pub fn remove<K>(&mut self, key: K) -> Option<Value>
where
K: AsRef<str>,
{
self.get_mut_extra().remove(key.as_ref())
}
}