Started adding doc to better build the system
This commit is contained in:
138
src/users.rs
138
src/users.rs
@@ -1,3 +1,29 @@
|
|||||||
|
//! # Authentication flow
|
||||||
|
//! Before being able to authenticate, the user needs to create an account
|
||||||
|
//! Here's how it can be done:
|
||||||
|
//! - The user submits information on the client
|
||||||
|
//! - The client sends a request to the "register" endpoint
|
||||||
|
//! - The endpoint ensures the information given is valid
|
||||||
|
//! - An account is created
|
||||||
|
//! - The user is redirected to the login page
|
||||||
|
//!
|
||||||
|
//! After, the user can authenticate
|
||||||
|
//! Here's how it works:
|
||||||
|
//! - The users submits information on the client
|
||||||
|
//! - The client sends a request to the "login" endpoint
|
||||||
|
//! - The endpoint makes sure the information given is valid (otherwise reject the request: no db call)
|
||||||
|
//! - Then it checks that the user exists
|
||||||
|
//! - Then it checks that the correct password was given
|
||||||
|
//! - Then it creates two tokens: a short-lived and a refresh-token
|
||||||
|
//! - The short-lived token must be saved in local-storage and the refresh-token must be saved as a http only cookie
|
||||||
|
//!
|
||||||
|
//! Once authenticated, the short-lived token can be renewed
|
||||||
|
//! Here's how it works:
|
||||||
|
//! - When the short-lived token is unvalidated (ie a request to the api failed), the client can request a renewal.
|
||||||
|
//! - The renewal request contains the now unvalid token with the refresh-token cookie.
|
||||||
|
//! - The server checks that the refresh-token is valid (good user, not expired, ...)
|
||||||
|
//! - If checks pass, the server generates a new short-lived token.
|
||||||
|
//! - If it fails, the client redirects the user to login.
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use crate::types::{User, UserLogin, UserRegister, UserTokenClaims};
|
use crate::types::{User, UserLogin, UserRegister, UserTokenClaims};
|
||||||
use actix_web::web::{Data, Json};
|
use actix_web::web::{Data, Json};
|
||||||
@@ -81,36 +107,37 @@ async fn logout(
|
|||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
app_state: Data<AppState>,
|
app_state: Data<AppState>,
|
||||||
) -> Result<impl Responder, Box<(dyn Error + 'static)>> {
|
) -> Result<impl Responder, Box<(dyn Error + 'static)>> {
|
||||||
|
todo!();
|
||||||
// Put the (KeyId, User) pair in the revoked table
|
// Put the (KeyId, User) pair in the revoked table
|
||||||
// And remove data from client
|
// And remove data from client
|
||||||
match req.headers().get("Authorization") {
|
// match req.headers().get("Authorization") {
|
||||||
Some(token) => {
|
// Some(token) => {
|
||||||
let token = token.to_str()?;
|
// let token = token.to_str()?;
|
||||||
let token = match token.split_once(" ") {
|
// let token = match token.split_once(" ") {
|
||||||
Some((_, token)) => token,
|
// Some((_, token)) => token,
|
||||||
None => return Ok(HttpResponse::BadRequest().finish()),
|
// None => return Ok(HttpResponse::BadRequest().finish()),
|
||||||
};
|
// };
|
||||||
let mut key = File::open("pub.pem")?;
|
// let mut key = File::open("pub.pem")?;
|
||||||
let mut buf = vec![];
|
// let mut buf = vec![];
|
||||||
key.read_to_end(&mut buf)?;
|
// key.read_to_end(&mut buf)?;
|
||||||
let token = decode::<UserTokenClaims>(
|
// let token = decode::<UserTokenClaims>(
|
||||||
token,
|
// token,
|
||||||
&DecodingKey::from_ec_pem(&buf).unwrap(),
|
// &DecodingKey::from_ec_pem(&buf).unwrap(),
|
||||||
&Validation::new(Algorithm::ES256),
|
// &Validation::new(Algorithm::ES256),
|
||||||
)?;
|
// )?;
|
||||||
let exp = token.claims.exp as i64;
|
// let exp = token.claims.exp as i64;
|
||||||
query!(
|
// query!(
|
||||||
"INSERT INTO revoked ( token_id, user_id, expires ) VALUES ( $1, $2, $3 )",
|
// "INSERT INTO revoked ( token_id, user_id, expires ) VALUES ( $1, $2, $3 )",
|
||||||
token.claims.kid,
|
// token.claims.kid,
|
||||||
token.claims.uid,
|
// token.claims.uid,
|
||||||
exp
|
// exp
|
||||||
)
|
// )
|
||||||
.execute(&app_state.database)
|
// .execute(&app_state.database)
|
||||||
.await?;
|
// .await?;
|
||||||
Ok(HttpResponse::Ok().finish())
|
// Ok(HttpResponse::Ok().finish())
|
||||||
}
|
// }
|
||||||
None => Ok(HttpResponse::BadRequest().finish()),
|
// None => Ok(HttpResponse::BadRequest().finish()),
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/register")]
|
#[post("/register")]
|
||||||
@@ -147,31 +174,32 @@ async fn verify_token(
|
|||||||
app_state: Data<AppState>,
|
app_state: Data<AppState>,
|
||||||
token: &str,
|
token: &str,
|
||||||
) -> Result<bool, Box<(dyn Error + 'static)>> {
|
) -> Result<bool, Box<(dyn Error + 'static)>> {
|
||||||
let mut key = File::open("pub.pem")?;
|
todo!();
|
||||||
let mut buf = vec![];
|
// let mut key = File::open("pub.pem")?;
|
||||||
key.read_to_end(&mut buf)?;
|
// let mut buf = vec![];
|
||||||
let token = decode::<UserTokenClaims>(
|
// key.read_to_end(&mut buf)?;
|
||||||
token,
|
// let token = decode::<UserTokenClaims>(
|
||||||
&DecodingKey::from_ec_pem(&buf).unwrap(),
|
// token,
|
||||||
&Validation::new(Algorithm::ES256),
|
// &DecodingKey::from_ec_pem(&buf).unwrap(),
|
||||||
)?;
|
// &Validation::new(Algorithm::ES256),
|
||||||
let exp = token.claims.exp as u64;
|
// )?;
|
||||||
let now = get_current_timestamp();
|
// let exp = token.claims.exp as u64;
|
||||||
if exp > now {
|
// let now = get_current_timestamp();
|
||||||
return Ok(false);
|
// if exp > now {
|
||||||
}
|
// return Ok(false);
|
||||||
let kid = token.claims.kid;
|
// }
|
||||||
let uid = token.claims.uid;
|
// let kid = token.claims.kid;
|
||||||
if query!(
|
// let uid = token.claims.uid;
|
||||||
"SELECT token_id FROM revoked WHERE token_id = $1 AND user_id = $2",
|
// if query!(
|
||||||
kid,
|
// "SELECT token_id FROM revoked WHERE token_id = $1 AND user_id = $2",
|
||||||
uid
|
// kid,
|
||||||
)
|
// uid
|
||||||
.fetch_optional(&app_state.database)
|
// )
|
||||||
.await?
|
// .fetch_optional(&app_state.database)
|
||||||
.is_some()
|
// .await?
|
||||||
{
|
// .is_some()
|
||||||
return Ok(false);
|
// {
|
||||||
}
|
// return Ok(false);
|
||||||
Ok(true)
|
// }
|
||||||
|
// Ok(true)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user