1use actix_web::dev::{ServiceRequest, ServiceResponse};
2use std::{rc::Rc, task::{Context, Poll}};
3use actix_web::Error;
4use actix_service::{Service, Transform};
5use futures::{future::{ok, LocalBoxFuture, Ready}};
6use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
7
8use crate::auth::claims::Claims;
9
10pub struct JwtMiddleware {
11 secret_key: String
12}
13
14impl JwtMiddleware{
15 pub fn new(secret_key: String) -> Self {
16 Self {
17 secret_key
18 }
19 }
20}
21
22impl<S, B> Transform<S, ServiceRequest> for JwtMiddleware
23where
24 S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
25 S::Future: 'static,
26 B: 'static
27{
28 type Response = ServiceResponse<B>;
29 type Error = Error;
30 type Transform = JwtMiddlewareService<S>;
31 type InitError = ();
32 type Future = Ready<Result<Self::Transform, Self::InitError>>;
33
34 fn new_transform(&self, service: S) -> Self::Future {
35 ok(JwtMiddlewareService {
36 service: Rc::new(service),
37 secret_key: self.secret_key.clone()
38 })
39 }
40}
41
42pub struct JwtMiddlewareService<S> {
43 service: Rc<S>,
44 secret_key: String,
45}
46
47impl<S, B> Service<ServiceRequest> for JwtMiddlewareService<S>
48where
49 S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
50 S::Future: 'static,
51{
52 type Response = ServiceResponse<B>;
53 type Error = Error;
54 type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
55
56 fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
57 self.service.poll_ready(cx)
58 }
59
60 fn call(&self, req: ServiceRequest) -> Self::Future {
61 let service = Rc::clone(&self.service);
62
63 let auth_header = match req.headers().get("Authorization") {
64 Some(header) => header,
65 None => {
66 return Box::pin(async {
67 Err(actix_web::error::ErrorUnauthorized("Authorization header missing"))
68 })
69 }
70 };
71
72 let auth_str = match auth_header.to_str() {
73 Ok(str) => str,
74 Err(_) => {
75 return Box::pin(async {
76 Err(actix_web::error::ErrorUnauthorized("Invalid Authorization header encoding"))
77 })
78 }
79 };
80
81 if !auth_str.starts_with("Bearer ") {
82 return Box::pin(async {
83 Err(actix_web::error::ErrorUnauthorized("Authorization header must start with 'Bearer '"))
84 })
85 }
86
87 let token = &auth_str[7..];
88
89 if token.is_empty() {
90 return Box::pin(async {
91 Err(actix_web::error::ErrorUnauthorized("Empty token"))
92 });
93 }
94
95 let mut validation = Validation::new(Algorithm::HS256);
96 validation.validate_exp = true;
97
98 let token_data = decode::<Claims<serde_json::Value>>( token,
100 &DecodingKey::from_secret(self.secret_key.as_bytes()),
101 &validation
102 );
103
104 match token_data {
105 Ok(_data) => {
106 return Box::pin(service.call(req))
107 },
108 Err(err) => {
109 let error_msg = match err.kind() {
110 jsonwebtoken::errors::ErrorKind::ExpiredSignature => "Token expired",
111 jsonwebtoken::errors::ErrorKind::InvalidToken => "Invalid token",
112 jsonwebtoken::errors::ErrorKind::InvalidSignature => "Invalid token signature",
113 jsonwebtoken::errors::ErrorKind::InvalidEcdsaKey => "Invalid key",
114 jsonwebtoken::errors::ErrorKind::InvalidAlgorithm => "Invalid algorithm",
115 jsonwebtoken::errors::ErrorKind::InvalidIssuer => "Invalid issuer",
116 jsonwebtoken::errors::ErrorKind::InvalidAudience => "Invalid audience",
117 jsonwebtoken::errors::ErrorKind::InvalidSubject => "Invalid subject",
118 jsonwebtoken::errors::ErrorKind::ImmatureSignature => "Token not yet valid",
119 _ => "Invalid token", };
121
122 Box::pin(async move {
123 Err(actix_web::error::ErrorUnauthorized(error_msg))
124 })
125 }
126 }
127 }
128}