implement auth/sign_in

This commit is contained in:
Peter Cai 2020-02-20 20:45:55 +08:00
parent 11b2a272b2
commit 77517147c8
No known key found for this signature in database
GPG key ID: 71F5FB4E4F3FD54F
5 changed files with 57 additions and 4 deletions

1
Cargo.lock generated
View file

@ -891,6 +891,7 @@ dependencies = [
"jwt", "jwt",
"rocket", "rocket",
"rocket_contrib", "rocket_contrib",
"rust-crypto",
"serde", "serde",
] ]

View file

@ -11,4 +11,5 @@ jwt = "0.4.0"
diesel = { version = "1.4.3", features = ["sqlite"] } diesel = { version = "1.4.3", features = ["sqlite"] }
diesel_migrations = "1.4.0" diesel_migrations = "1.4.0"
dotenv = "0.9.0" dotenv = "0.9.0"
serde = { version = "1.0.104", features = ["derive"] } serde = { version = "1.0.104", features = ["derive"] }
rust-crypto = "0.2.36"

View file

@ -3,12 +3,13 @@ use crate::user;
use rocket::http::Status; use rocket::http::Status;
use rocket::response::status::Custom; use rocket::response::status::Custom;
use rocket_contrib::json::Json; use rocket_contrib::json::Json;
use serde::Serialize; use serde::{Serialize, Deserialize};
use std::vec::Vec; use std::vec::Vec;
pub fn routes() -> impl Into<Vec<rocket::Route>> { pub fn routes() -> impl Into<Vec<rocket::Route>> {
routes![ routes![
auth, auth,
auth_sign_in,
auth_params auth_params
] ]
} }
@ -43,8 +44,31 @@ struct AuthResult {
#[post("/auth", format = "json", data = "<new_user>")] #[post("/auth", format = "json", data = "<new_user>")]
fn auth(db: DbConn, new_user: Json<user::NewUser>) -> Custom<JsonResp<AuthResult>> { fn auth(db: DbConn, new_user: Json<user::NewUser>) -> Custom<JsonResp<AuthResult>> {
match user::User::create(&db.0, &new_user) { match user::User::create(&db.0, &new_user) {
Ok(_) => success_resp(AuthResult { Ok(_) => _sign_in(db, &new_user.email, &new_user.password),
token: "aaaa".to_string() Err(user::UserOpError(e)) =>
error_resp(Status::InternalServerError, vec![e])
}
}
#[derive(Deserialize)]
struct SignInParams {
email: String,
password: String
}
#[post("/auth/sign_in", format = "json", data = "<params>")]
fn auth_sign_in(db: DbConn, params: Json<SignInParams>) -> Custom<JsonResp<AuthResult>> {
_sign_in(db, &params.email, &params.password)
}
// Shared logic for all interfaces that needs to do an automatic sign-in
fn _sign_in(db: DbConn, mail: &str, passwd: &str) -> Custom<JsonResp<AuthResult>> {
// Try to find the user first
let res = user::User::find_user_by_email(&db, mail)
.and_then(|u| u.create_token(passwd));
match res {
Ok(token) => success_resp(AuthResult {
token
}), }),
Err(user::UserOpError(e)) => Err(user::UserOpError(e)) =>
error_resp(Status::InternalServerError, vec![e]) error_resp(Status::InternalServerError, vec![e])

View file

@ -11,6 +11,7 @@ extern crate diesel_migrations;
extern crate dotenv; extern crate dotenv;
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
extern crate crypto;
mod schema; mod schema;
mod api; mod api;

View file

@ -3,6 +3,8 @@ use crate::schema::users::dsl::*;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::sqlite::SqliteConnection; use diesel::sqlite::SqliteConnection;
use serde::Deserialize; use serde::Deserialize;
use std::env;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug)] #[derive(Debug)]
pub struct UserOpError(pub String); pub struct UserOpError(pub String);
@ -56,4 +58,28 @@ impl User {
Result::Ok(results.remove(0)) // Take ownership, kill the stupid Vec Result::Ok(results.remove(0)) // Take ownership, kill the stupid Vec
} }
} }
// Create a JWT token for the current user if password matches
pub fn create_token(&self, passwd: &str) -> Result<String, UserOpError> {
if passwd != self.password {
Err(UserOpError::new("Password mismatch"))
} else {
jwt::Token::new(
jwt::Header::default(),
jwt::Claims::new(jwt::Registered {
iss: None,
sub: Some(self.email.clone()),
exp: None,
aud: None,
nbf: Some(SystemTime::now().duration_since(UNIX_EPOCH)
.expect("wtf????").as_secs()),
iat: None,
jti: None
})
).signed(env::var("SFRS_JWT_SECRET")
.expect("Please have SFRS_JWT_SECRET set")
.as_bytes(), crypto::sha2::Sha256::new())
.map_err(|_| UserOpError::new("Failed to generate token"))
}
}
} }