From c85bb0ef72a642a5667e85654e79c73fea31e129 Mon Sep 17 00:00:00 2001 From: Marko Korhonen Date: Thu, 9 Apr 2020 11:52:31 +0300 Subject: [PATCH] Register works, login almost --- project/src/handlers/authentication.rs | 50 +++++++++++++++++++++++++- project/src/handlers/mod.rs | 1 - project/src/handlers/register.rs | 19 ---------- project/src/main.rs | 21 ++++++----- project/src/models/user.rs | 3 +- project/src/utils/jwt.rs | 26 +++++++++----- 6 files changed, 79 insertions(+), 41 deletions(-) delete mode 100644 project/src/handlers/register.rs diff --git a/project/src/handlers/authentication.rs b/project/src/handlers/authentication.rs index d0468bc..3f2c48d 100644 --- a/project/src/handlers/authentication.rs +++ b/project/src/handlers/authentication.rs @@ -1 +1,49 @@ -pub fn login() {} +use crate::{ + db_connection::DbPool, + errors::CustomError, + handlers::pool_handler, + models::user::{AuthUser, RegisterUser, User}, + utils::jwt::*, +}; + +use actix_identity::Identity; +use actix_web::{post, web, HttpResponse, Responder}; + +#[post("/auth/register")] +pub async fn register( + new_user: web::Json, + pool: web::Data, +) -> impl Responder { + let connection = pool_handler(pool)?; + let register_user = new_user + .into_inner() + .validation() + .map_err(|e| HttpResponse::InternalServerError().json(e.to_string()))?; + + User::create(register_user, &connection) + .map(|user| HttpResponse::Ok().json(user)) + .map_err(|e| HttpResponse::InternalServerError().json(e.to_string())) +} + +#[post("auth/login")] +pub async fn login( + id: Identity, + auth_user: web::Json, + pool: web::Data, +) -> impl Responder { + let connection = pool_handler(pool)?; + + let user = auth_user.login(&connection).map_err(|e| match e { + CustomError::DBError(diesel::result::Error::NotFound) => { + HttpResponse::NotFound().json(e.to_string()) + } + _ => HttpResponse::InternalServerError().json(e.to_string()), + })?; + + let token = new_token(user.id, &user.username, &user.admin).map_err(|e| match e { + _ => HttpResponse::InternalServerError().finish(), + })?; + + id.remember(token); + Ok(HttpResponse::Ok().json(token)) +} diff --git a/project/src/handlers/mod.rs b/project/src/handlers/mod.rs index 24edc59..7e04bcd 100644 --- a/project/src/handlers/mod.rs +++ b/project/src/handlers/mod.rs @@ -1,5 +1,4 @@ pub mod authentication; -pub mod register; use crate::db_connection::{DbPool, MyPooledConnection}; use actix_web::{web, HttpResponse}; diff --git a/project/src/handlers/register.rs b/project/src/handlers/register.rs deleted file mode 100644 index 0e89e81..0000000 --- a/project/src/handlers/register.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::db_connection::DbPool; -use crate::handlers::pool_handler; -use crate::models::user::{RegisterUser, User}; -use actix_web::{web, HttpResponse}; - -pub fn register( - new_user: web::Json, - pool: web::Data, -) -> Result { - let my_pool = pool_handler(pool)?; - let register_user = new_user - .into_inner() - .validation() - .map_err(|e| HttpResponse::InternalServerError().json(e.to_string()))?; - - User::create(register_user, &my_pool) - .map(|user| HttpResponse::Ok().json(user)) - .map_err(|e| HttpResponse::InternalServerError().json(e.to_string())) -} diff --git a/project/src/main.rs b/project/src/main.rs index 93bae7d..2bb535c 100644 --- a/project/src/main.rs +++ b/project/src/main.rs @@ -1,26 +1,28 @@ #[macro_use] extern crate diesel; -extern crate csrf; extern crate dotenv; -#[macro_use] -extern crate dotenv_codegen; pub mod db_connection; pub mod errors; pub mod handlers; pub mod models; pub mod schema; +pub mod utils; use actix_cors::Cors; use actix_identity::{CookieIdentityPolicy, IdentityService}; -use actix_web::{http::header, middleware::Logger, web, App, HttpServer}; +use actix_web::{http::header, middleware::Logger, App, HttpServer}; use chrono::Duration; use db_connection::get_pool; +use dotenv::dotenv; +use handlers::authentication; +use std::env; #[actix_rt::main] async fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=debug,diesel=debug"); env_logger::init(); + dotenv().ok(); let bind = "localhost:8080"; println!("Starting server at: http://{}", &bind); @@ -30,7 +32,7 @@ async fn main() -> std::io::Result<()> { .wrap(Logger::default()) .wrap( Cors::new() - .allowed_origin(dotenv!("ALLOWED_ORIGIN")) + .allowed_origin(env::var("ALLOWED_ORIGIN").expect("ALLOWED_ORIGIN").as_str()) .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"]) .allowed_headers(vec![ header::AUTHORIZATION, @@ -41,15 +43,16 @@ async fn main() -> std::io::Result<()> { .finish(), ) .wrap(IdentityService::new( - CookieIdentityPolicy::new(dotenv!("SECRET").as_bytes()) - .domain(dotenv!("DOMAIN")) + CookieIdentityPolicy::new(env::var("SECRET").expect("SECRET").as_bytes()) + .domain(env::var("DOMAIN").expect("DOMAIN")) .name("thesis") .path("/") .max_age(Duration::days(1).num_seconds()) - .secure(dotenv!("COOKIE_SECURE").parse().unwrap()), + .secure(false), )) .data(get_pool()) - .service(web::resource("/register").route(web::post().to(handlers::register::register))) + .service(authentication::register) + .service(authentication::login) }) .bind(&bind)? .run() diff --git a/project/src/models/user.rs b/project/src/models/user.rs index 4db287d..2a567b9 100644 --- a/project/src/models/user.rs +++ b/project/src/models/user.rs @@ -1,5 +1,4 @@ -use crate::errors::CustomError; -use crate::schema::users; +use crate::{errors::CustomError, schema::users}; use bcrypt::{hash, verify, DEFAULT_COST}; use chrono::{Local, NaiveDateTime}; use diesel::prelude::*; diff --git a/project/src/utils/jwt.rs b/project/src/utils/jwt.rs index 490bed0..ce83f0b 100644 --- a/project/src/utils/jwt.rs +++ b/project/src/utils/jwt.rs @@ -1,17 +1,21 @@ extern crate bcrypt; +extern crate jsonwebtoken; use actix_web::HttpResponse; use chrono::{Duration, Local}; -use jwt::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; +use jsonwebtoken::{decode, encode, Header, Validation}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct Claims { - sub: String, + sub: i32, + name: String, admin: bool, exp: usize, } pub struct UserWithToken { + pub id: i32, pub username: String, pub admin: bool, } @@ -19,27 +23,31 @@ pub struct UserWithToken { impl From for UserWithToken { fn from(claims: Claims) -> Self { UserWithToken { - username: claims.sub, + id: claims.sub, + username: claims.name, admin: claims.admin, } } } impl Claims { - fn with_username(username: &str, admin: &bool) -> Self { + fn with_username(id: i32, username: &str, admin: bool) -> Self { Claims { - sub: email.into(), - admin: admin.into(), + sub: id, + name: username.into(), + admin, exp: (Local::now() + Duration::hours(24)).timestamp() as usize, } } } -pub fn new_token(username: &str) -> Result { - let secret = dotenv!("JWT_SECRET").as_bytes(); +fn get_secret() -> [u8] { + std::env::var("JWT_SECRET").expect("JWT_SECRET").as_bytes() +} +pub fn new_token(id: i32, username: &str, admin: &bool) -> Result { let claims = Claims::with_username(username, admin); - encode(&Header::default(), &claims, secret) + encode(&Header::default(), &claims, get_secret()) .map_err(|e| HttpResponse::InternalServerError().json(e.to_string())) }