-
Notifications
You must be signed in to change notification settings - Fork 605
/
current_user.rs
87 lines (72 loc) · 2.78 KB
/
current_user.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
83
84
85
86
87
use super::prelude::*;
use conduit_cookie::RequestSession;
use diesel::prelude::*;
use crate::db::RequestTransaction;
use crate::util::errors::{std_error, CargoResult, ChainError, Unauthorized};
use crate::models::User;
use crate::schema::users;
#[derive(Debug, Clone, Copy)]
pub struct CurrentUser;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum AuthenticationSource {
SessionCookie,
ApiToken { auth_header: String },
}
impl Middleware for CurrentUser {
fn before(&self, req: &mut dyn Request) -> Result<(), Box<dyn Error + Send>> {
// Check if the request has a session cookie with a `user_id` property inside
let id = {
req.session()
.get("user_id")
.and_then(|s| s.parse::<i32>().ok())
};
let conn = req.db_conn().map_err(std_error)?;
if let Some(id) = id {
// If it did, look for a user in the database with the given `user_id`
let maybe_user = users::table.find(id).first::<User>(&*conn);
drop(conn);
if let Ok(user) = maybe_user {
// Attach the `User` model from the database to the request
req.mut_extensions().insert(user);
req.mut_extensions()
.insert(AuthenticationSource::SessionCookie);
}
} else {
// Otherwise, look for an `Authorization` header on the request
// and try to find a user in the database with a matching API token
let user_auth = if let Some(headers) = req.headers().find("Authorization") {
let auth_header = headers[0].to_string();
User::find_by_api_token(&conn, &auth_header)
.map(|user| (AuthenticationSource::ApiToken { auth_header }, user))
.optional()
.map_err(|e| Box::new(e) as Box<dyn Error + Send>)?
} else {
None
};
drop(conn);
if let Some((api_token, user)) = user_auth {
// Attach the `User` model from the database and the API token to the request
req.mut_extensions().insert(user);
req.mut_extensions().insert(api_token);
}
}
Ok(())
}
}
pub trait RequestUser {
fn user(&self) -> CargoResult<&User>;
fn authentication_source(&self) -> CargoResult<AuthenticationSource>;
}
impl<'a> RequestUser for dyn Request + 'a {
fn user(&self) -> CargoResult<&User> {
self.extensions()
.find::<User>()
.chain_error(|| Unauthorized)
}
fn authentication_source(&self) -> CargoResult<AuthenticationSource> {
self.extensions()
.find::<AuthenticationSource>()
.cloned()
.chain_error(|| Unauthorized)
}
}