-
-
Notifications
You must be signed in to change notification settings - Fork 794
/
auth_handler.rs
82 lines (67 loc) · 2.2 KB
/
auth_handler.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use std::future::{ready, Ready};
use actix_identity::Identity;
use actix_web::{
dev::Payload, web, Error, FromRequest, HttpMessage as _, HttpRequest, HttpResponse,
};
use diesel::prelude::*;
use serde::Deserialize;
use crate::{
errors::ServiceError,
models::{Pool, SlimUser, User},
utils::verify,
};
#[derive(Debug, Deserialize)]
pub struct AuthData {
pub email: String,
pub password: String,
}
// we need the same data
// simple aliasing makes the intentions clear and its more readable
pub type LoggedUser = SlimUser;
impl FromRequest for LoggedUser {
type Error = Error;
type Future = Ready<Result<LoggedUser, Error>>;
fn from_request(req: &HttpRequest, pl: &mut Payload) -> Self::Future {
if let Ok(identity) = Identity::from_request(req, pl).into_inner() {
if let Ok(user_json) = identity.id() {
if let Ok(user) = serde_json::from_str(&user_json) {
return ready(Ok(user));
}
}
}
ready(Err(ServiceError::Unauthorized.into()))
}
}
pub async fn logout(id: Identity) -> HttpResponse {
id.logout();
HttpResponse::NoContent().finish()
}
pub async fn login(
req: HttpRequest,
auth_data: web::Json<AuthData>,
pool: web::Data<Pool>,
) -> Result<HttpResponse, actix_web::Error> {
let user = web::block(move || query(auth_data.into_inner(), pool)).await??;
let user_string = serde_json::to_string(&user).unwrap();
Identity::login(&req.extensions(), user_string).unwrap();
Ok(HttpResponse::NoContent().finish())
}
pub async fn get_me(logged_user: LoggedUser) -> HttpResponse {
HttpResponse::Ok().json(logged_user)
}
/// Diesel query
fn query(auth_data: AuthData, pool: web::Data<Pool>) -> Result<SlimUser, ServiceError> {
use crate::schema::users::dsl::{email, users};
let mut conn = pool.get().unwrap();
let mut items = users
.filter(email.eq(&auth_data.email))
.load::<User>(&mut conn)?;
if let Some(user) = items.pop() {
if let Ok(matching) = verify(&user.hash, &auth_data.password) {
if matching {
return Ok(user.into());
}
}
}
Err(ServiceError::Unauthorized)
}