Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ r2d2 = "0.8.8"
#Password hashing
rust-argon2 = "0.8.1"

uuid = { version = "0.8.1", features = ["v4"] }
uuid = { version = "0.8.1", features = ["v4"] }

# async futures
futures = "0.3.4"
8 changes: 8 additions & 0 deletions http/private.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
GET http://127.0.0.1:8000/private/
Content-Type: application/json
Authorization: abef35bd-cc80-4514-82c1-1d00e3e3205c

{
"email": "d.sai535@gmail.com",
"password": "sasas"
}
1 change: 0 additions & 1 deletion src/auth/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ pub async fn user_login(body: Json<UserLogin>, db: Data<Pool>, redis: Data<Redis
let token_payload = to_value(UserLoginToken {
id: rows.get(0).unwrap().get("id"),
email: rows.get(0).unwrap().get("email"),

}).unwrap().to_string();
set_redis::<String>(redis, &token, token_payload);
HttpResponse::Ok().json(LoginResponse{
Expand Down
10 changes: 9 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ mod models;
mod utils;
mod types;

// private routes
mod private;

// middleware
mod middleware;

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
// loading .env file
Expand All @@ -35,5 +41,7 @@ async fn main() -> std::io::Result<()> {
.data(redis_client.clone())
.service(auth::auth_routes())
.service(Json::json_routes())
.service(private::register_private()
.wrap(middleware::private::CheckToken))
}).bind("127.0.0.1:8000")?.run().await
}
}
1 change: 1 addition & 0 deletions src/middleware/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod private;
73 changes: 73 additions & 0 deletions src/middleware/private.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::task::{Context, Poll};

use actix_web::dev::{ServiceRequest, ServiceResponse, Transform, Service};
use actix_web::{Error, HttpResponse};
use futures::future::{ok, Either, Ready};
use actix_web::web::Data;
use r2d2_redis::redis::{RedisResult};
use crate::utils::redis_utils::{RedisClient, get_redis};

pub struct CheckToken;

impl<S, B> Transform<S> for CheckToken
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Transform = CheckTokenMiddleware<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;

fn new_transform(&self, service: S) -> Self::Future {
ok(CheckTokenMiddleware { service })
}
}

pub struct CheckTokenMiddleware<S> {
service: S,
}

pub fn verify_token(req: &ServiceRequest, token: &str) -> RedisResult<String> {
let redis: Data<RedisClient> = req.app_data().unwrap();
get_redis(redis, token)
}

impl<S, B> Service for CheckTokenMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>;

fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}

fn call(&mut self, req: ServiceRequest) -> Self::Future {
let token = req.headers().get("Authorization");
if token == None {
return Either::Right(ok(req.into_response(
HttpResponse::Unauthorized()
.body("Token is missing") // you can swap body with json
.into_body(),
)));
}
let is_valid_token = verify_token(&req, token.unwrap().to_str().unwrap());
if is_valid_token.is_err() {
Either::Right(ok(req.into_response(
HttpResponse::Unauthorized()
.body("Check token") // you can swap body with json
.into_body(),
)))
} else {
Either::Left(self.service.call(req))
}

}
}
12 changes: 12 additions & 0 deletions src/private/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use actix_web::{
web::{get, scope},
HttpResponse, Scope,
};

async fn private() -> HttpResponse {
HttpResponse::Ok().body("Hello World!")
}

pub fn register_private() -> Scope {
scope("/private").route("/", get().to(private))
}
7 changes: 6 additions & 1 deletion src/utils/redis_utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use r2d2_redis::{r2d2, RedisConnectionManager};
use std::env::var;
use r2d2::Pool;
use r2d2_redis::redis::{cmd, ToRedisArgs};
use r2d2_redis::redis::{cmd, ToRedisArgs, RedisResult};
use actix_web::web::Data;

pub type RedisClient = Pool<RedisConnectionManager>;
Expand All @@ -17,4 +17,9 @@ pub fn connect_redis() -> RedisClient {
pub fn set_redis<T: ToRedisArgs>(client: Data<RedisClient>, key: &String, payload: T) {
let mut pool = client.get().unwrap();
cmd("SET").arg(key).arg(payload).execute(&mut *pool)
}

pub fn get_redis(client: Data<RedisClient>, token: &str) -> RedisResult<String> {
let mut pool = client.get().unwrap();
cmd("GET").arg(token).query(&mut *pool)
}