implement auth/sign_in
This commit is contained in:
parent
11b2a272b2
commit
77517147c8
|
@ -891,6 +891,7 @@ dependencies = [
|
|||
"jwt",
|
||||
"rocket",
|
||||
"rocket_contrib",
|
||||
"rust-crypto",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
|
@ -11,4 +11,5 @@ jwt = "0.4.0"
|
|||
diesel = { version = "1.4.3", features = ["sqlite"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
dotenv = "0.9.0"
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
rust-crypto = "0.2.36"
|
30
src/api.rs
30
src/api.rs
|
@ -3,12 +3,13 @@ use crate::user;
|
|||
use rocket::http::Status;
|
||||
use rocket::response::status::Custom;
|
||||
use rocket_contrib::json::Json;
|
||||
use serde::Serialize;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::vec::Vec;
|
||||
|
||||
pub fn routes() -> impl Into<Vec<rocket::Route>> {
|
||||
routes![
|
||||
auth,
|
||||
auth_sign_in,
|
||||
auth_params
|
||||
]
|
||||
}
|
||||
|
@ -43,8 +44,31 @@ struct AuthResult {
|
|||
#[post("/auth", format = "json", data = "<new_user>")]
|
||||
fn auth(db: DbConn, new_user: Json<user::NewUser>) -> Custom<JsonResp<AuthResult>> {
|
||||
match user::User::create(&db.0, &new_user) {
|
||||
Ok(_) => success_resp(AuthResult {
|
||||
token: "aaaa".to_string()
|
||||
Ok(_) => _sign_in(db, &new_user.email, &new_user.password),
|
||||
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, ¶ms.email, ¶ms.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)) =>
|
||||
error_resp(Status::InternalServerError, vec![e])
|
||||
|
|
|
@ -11,6 +11,7 @@ extern crate diesel_migrations;
|
|||
extern crate dotenv;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
extern crate crypto;
|
||||
|
||||
mod schema;
|
||||
mod api;
|
||||
|
|
26
src/user.rs
26
src/user.rs
|
@ -3,6 +3,8 @@ use crate::schema::users::dsl::*;
|
|||
use diesel::prelude::*;
|
||||
use diesel::sqlite::SqliteConnection;
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UserOpError(pub String);
|
||||
|
@ -56,4 +58,28 @@ impl User {
|
|||
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"))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue