use std::future::{Ready, ready}; use actix_web::{FromRequest, http, HttpRequest, dev::Payload, web::Data}; use chrono::Utc; use jsonwebtoken::{encode, Header, EncodingKey, decode, DecodingKey, Validation}; use serde::{Serialize, Deserialize}; use uuid::Uuid; use crate::{schema::user::{User, get_user}, DbPool}; use super::error::ApiError; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { exp: i64, uid: Uuid } fn get_claims(req: &HttpRequest) -> Result { let token = req.headers() .get(http::header::AUTHORIZATION) .map(|h| h.to_str().unwrap().split_at(7).1.to_string()); let token = token.ok_or(ApiError{ status: 400, message: "JWT-token was not specified in the Authorization header as Bearer: token".to_string() })?; let secret = "secret"; Ok(decode::(token.as_str(), &DecodingKey::from_secret(secret.as_bytes()), &Validation::default())?.claims) } pub fn get_token(user: &User) -> Result { let claims = Claims { exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), uid: user.id, }; let secret = "secret"; Ok(encode( &Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))?) } impl FromRequest for User { type Error = ApiError; type Future = Ready>; fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { ready( (|| -> Result{ let pool = req.app_data::>().expect("No database configured"); let mut conn = pool.get().expect("couldn't get db connection from pool"); let uid = get_claims(req)?.uid; Ok(get_user(&mut conn, uid)?) })() ) } }