1use std::sync::Arc;
2
3use chrono::{Duration, Utc};
4use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
5use crate::di::Container;
6
7use super::claims::RuestClaims;
8use super::config::SecurityConfig;
9use super::SecurityError;
10
11#[derive(Clone)]
13pub struct JwtService {
14 encoding: EncodingKey,
15 decoding: DecodingKey,
16 validation: Validation,
17 expires_in_secs: u64,
18 issuer: Option<String>,
19}
20
21impl JwtService {
22 pub fn new(config: &SecurityConfig) -> Result<Self, SecurityError> {
23 if config.jwt_secret.len() < 16 {
24 return Err(SecurityError::Config(
25 "jwt_secret must be at least 16 characters".into(),
26 ));
27 }
28
29 let mut validation = Validation::default();
30 validation.validate_exp = true;
31 if let Some(ref iss) = config.jwt_issuer {
32 validation.set_issuer(&[iss.as_str()]);
33 }
34
35 Ok(Self {
36 encoding: EncodingKey::from_secret(config.jwt_secret.as_bytes()),
37 decoding: DecodingKey::from_secret(config.jwt_secret.as_bytes()),
38 validation,
39 expires_in_secs: config.jwt_expires_in_secs,
40 issuer: config.jwt_issuer.clone(),
41 })
42 }
43
44 pub fn register_provider(container: &Container, config: SecurityConfig) -> Result<(), SecurityError> {
46 let service = Arc::new(Self::new(&config)?);
47 container.register_singleton(service);
48 Ok(())
49 }
50
51 pub fn register_dev_provider(container: &Container) {
53 let config = SecurityConfig::dev();
54 let service = Arc::new(Self::new(&config).expect("dev JWT config"));
55 container.register_singleton(service);
56 }
57
58 pub fn sign_subject(&self, sub: impl Into<String>, roles: Vec<String>) -> Result<String, SecurityError> {
59 let now = Utc::now();
60 let exp = now + Duration::seconds(self.expires_in_secs as i64);
61 let claims = RuestClaims::new(
62 sub,
63 roles,
64 self.issuer.clone(),
65 exp.timestamp(),
66 now.timestamp(),
67 );
68 self.sign(&claims)
69 }
70
71 pub fn sign(&self, claims: &RuestClaims) -> Result<String, SecurityError> {
72 encode(&Header::default(), claims, &self.encoding).map_err(SecurityError::from)
73 }
74
75 pub fn verify(&self, token: &str) -> Result<RuestClaims, SecurityError> {
76 let data = decode::<RuestClaims>(token, &self.decoding, &self.validation)
77 .map_err(|_| SecurityError::InvalidToken)?;
78 Ok(data.claims)
79 }
80}