1use chrono::{Duration, Utc};
2use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, encode};
3use serde::{Deserialize, Serialize};
4use server_config::{jwt::JwtConfig, uri::IgnoreUri};
5
6use crate::error::auth::AuthError;
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
10pub struct Claims {
11 pub sub: String, pub exp: i64, pub iat: i64, pub data: Option<String>,
15}
16
17pub struct JwtService {
19 config: JwtConfig,
20}
21
22impl JwtService {
23 pub fn new(mut config: JwtConfig) -> Self {
24 if let Some(data) = &mut config.ignore_uris {
25 JwtService::methods_to_uppercase(data);
26 }
27 Self { config }
28 }
29
30 pub fn generate_token(
32 &self,
33 user_info: &str,
34 data: Option<String>,
35 ) -> Result<String, jsonwebtoken::errors::Error> {
36 let now = Utc::now();
37 let exp = now + Duration::hours(self.config.expiration_hours);
38
39 let claims = Claims {
40 sub: user_info.to_string(),
41 exp: exp.timestamp(),
42 iat: now.timestamp(),
43 data,
44 };
45
46 encode(
47 &Header::default(),
48 &claims,
49 &EncodingKey::from_secret(self.config.secret.as_ref()),
50 )
51 }
52
53 pub fn verify_token(&self, token: &str) -> Result<Claims, AuthError> {
55 let token_data = decode::<Claims>(
56 token,
57 &DecodingKey::from_secret(self.config.secret.as_ref()),
58 &Validation::new(Algorithm::HS256),
59 )
60 .map_err(|_| AuthError::InvalidToken)?;
61
62 let now = Utc::now().timestamp();
64 if token_data.claims.exp < now {
65 return Err(AuthError::ExpiredToken);
66 }
67
68 Ok(token_data.claims)
69 }
70
71 pub fn get_secret(&self) -> String {
73 self.config.secret.clone()
74 }
75
76 pub fn get_expiration(&self) -> i64 {
78 self.config.expiration_hours
79 }
80
81 pub fn is_ignore_uri(&self, uri: &str, method: &str) -> bool {
83 if let Some(data) = &self.config.ignore_uris {
84 for item in data.iter() {
85 if uri.starts_with(&item.path) && item.method.contains(&method.to_uppercase()) {
87 return true;
88 }
89 }
90 false
91 } else {
92 false
93 }
94 }
95
96 pub fn methods_to_uppercase(data: &mut [IgnoreUri]) {
98 for item in data.iter_mut() {
99 for method in item.method.iter_mut() {
100 *method = method.to_uppercase();
101 }
102 }
103 }
104}