1use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
2use serde::{Deserialize, Serialize};
3use std::time::{SystemTime, UNIX_EPOCH};
4use crate::Result;
5
6#[derive(Debug, Serialize, Deserialize, Clone)]
8pub struct Claims {
9 pub sub: String, pub exp: usize, pub iat: usize, pub nbf: usize, #[serde(skip_serializing_if = "Option::is_none")]
14 pub roles: Option<Vec<String>>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub permissions: Option<Vec<String>>,
17}
18
19impl Claims {
20 pub fn new(user_id: String, expiry_secs: u64) -> Self {
21 let now = SystemTime::now()
22 .duration_since(UNIX_EPOCH)
23 .unwrap()
24 .as_secs() as usize;
25
26 Self {
27 sub: user_id,
28 exp: now + expiry_secs as usize,
29 iat: now,
30 nbf: now,
31 roles: None,
32 permissions: None,
33 }
34 }
35
36 pub fn with_roles(mut self, roles: Vec<String>) -> Self {
37 self.roles = Some(roles);
38 self
39 }
40
41 pub fn with_permissions(mut self, permissions: Vec<String>) -> Self {
42 self.permissions = Some(permissions);
43 self
44 }
45
46 pub fn has_role(&self, role: &str) -> bool {
47 self.roles
48 .as_ref()
49 .map(|roles| roles.iter().any(|r| r == role))
50 .unwrap_or(false)
51 }
52
53 pub fn has_permission(&self, permission: &str) -> bool {
54 self.permissions
55 .as_ref()
56 .map(|perms| perms.iter().any(|p| p == permission))
57 .unwrap_or(false)
58 }
59}
60
61pub struct JwtManager {
63 secret: String,
64}
65
66impl JwtManager {
67 pub fn new(secret: String) -> Self {
68 Self { secret }
69 }
70
71 pub fn generate_token<T: Serialize>(&self, claims: &T) -> Result<String> {
72 let token = encode(
73 &Header::default(),
74 claims,
75 &EncodingKey::from_secret(self.secret.as_bytes()),
76 )?;
77 Ok(token)
78 }
79
80 pub fn verify(&self, token: &str) -> Result<Claims> {
81 let token_data = decode::<Claims>(
82 token,
83 &DecodingKey::from_secret(self.secret.as_bytes()),
84 &Validation::default(),
85 )?;
86 Ok(token_data.claims)
87 }
88}
89
90pub fn create_token(user_id: String, secret: &str, expiry_secs: u64) -> Result<String> {
92 let claims = Claims::new(user_id, expiry_secs);
93 let jwt = JwtManager::new(secret.to_string());
94 jwt.generate_token(&claims)
95}
96
97pub fn verify_token(token: &str, secret: &str) -> Result<Claims> {
99 let jwt = JwtManager::new(secret.to_string());
100 jwt.verify(token)
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_create_and_verify_token() {
109 let secret = "test_secret_key";
110 let user_id = "user123";
111
112 let token = create_token(user_id.to_string(), secret, 3600).unwrap();
113 let claims = verify_token(&token, secret).unwrap();
114
115 assert_eq!(claims.sub, user_id);
116 }
117
118 #[test]
119 fn test_claims_with_roles() {
120 let claims = Claims::new("user123".to_string(), 3600)
121 .with_roles(vec!["admin".to_string(), "user".to_string()]);
122
123 assert!(claims.has_role("admin"));
124 assert!(claims.has_role("user"));
125 assert!(!claims.has_role("guest"));
126 }
127}