Change from auth layer to using is_authorized function
This commit is contained in:
parent
042f6b17aa
commit
ef9951fcbe
|
|
@ -13,7 +13,7 @@ mod middlewares;
|
|||
mod routes;
|
||||
|
||||
use error_handling::AppError;
|
||||
use middlewares::{check_auth, inject_user_data};
|
||||
use middlewares::inject_user_data;
|
||||
use google_oauth::{login, logout, google_auth_return};
|
||||
use routes::{dashboard, index, about, profile, user_profile, useradmin};
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ async fn main() {
|
|||
.route("/login", get(login))
|
||||
.route("/logout", get(logout))
|
||||
.route("/google_auth_return", get(google_auth_return))
|
||||
.route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), check_auth))
|
||||
//.route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), check_auth))
|
||||
.route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), inject_user_data))
|
||||
.with_state(app_state.db_pool)
|
||||
.layer(Extension(user_data))
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use axum::{
|
|||
extract::State,
|
||||
http::Request,
|
||||
middleware::Next,
|
||||
response::{IntoResponse, Redirect},
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::TypedHeader;
|
||||
use chrono::Utc;
|
||||
|
|
@ -19,11 +19,8 @@ pub async fn inject_user_data(
|
|||
mut request: Request<Body>,
|
||||
next: Next,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
println!("inject_user_data : Injecting user data");
|
||||
if let Some(cookie) = cookie {
|
||||
println!("inject_user_data : {:#?}", cookie.get("session_token"));
|
||||
if let Some(session_token) = cookie.get("session_token") {
|
||||
println!("inject_user_data : Found session token: {}", session_token);
|
||||
let session_token: Vec<&str> = session_token.split('_').collect();
|
||||
let query: Result<(i64, i64, String), _> = sqlx::query_as(
|
||||
r#"SELECT user_id,expires_at,session_token_p2 FROM user_sessions WHERE session_token_p1=?"#,
|
||||
|
|
@ -46,7 +43,6 @@ pub async fn inject_user_data(
|
|||
session_token_p2_db,
|
||||
) {
|
||||
let id = query.0;
|
||||
println!("inject_user_data : Found user: {}", id);
|
||||
let expires_at = query.1;
|
||||
if expires_at > Utc::now().timestamp() {
|
||||
let row = sqlx::query_as!(
|
||||
|
|
@ -62,10 +58,8 @@ pub async fn inject_user_data(
|
|||
email: row.email,
|
||||
name: row.name,
|
||||
family_name: row.family_name,
|
||||
given_name: row.given_name,
|
||||
given_name: row.given_name
|
||||
}));
|
||||
} else {
|
||||
println!("inject_user_data : Session expired");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -77,59 +71,22 @@ pub async fn inject_user_data(
|
|||
Ok(next.run(request).await)
|
||||
}
|
||||
|
||||
pub async fn check_auth(
|
||||
State(app_state): State<SqlitePool>,
|
||||
request: Request<Body>,
|
||||
next: Next,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
println!("check_auth : Starting");
|
||||
//println!("{:#?}", request);
|
||||
if request
|
||||
.extensions()
|
||||
.get::<Option<UserData>>()
|
||||
.ok_or("check_auth: extensions have no UserData")?
|
||||
.is_some()
|
||||
{
|
||||
let path = &*request.uri().to_string();
|
||||
println!(
|
||||
"check_auth : {}",
|
||||
&*request
|
||||
.extensions()
|
||||
.get::<Option<UserData>>()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.email
|
||||
);
|
||||
|
||||
pub async fn is_authorized(path: &str, user_data: Option<UserData>, db_pool: SqlitePool) -> bool {
|
||||
if let Some(user_data) = user_data {
|
||||
let query: Result<(i64,), _> = match path {
|
||||
"/profile" => {
|
||||
sqlx::query_as(r#"select u.id from users u where email =?"#)
|
||||
.bind(
|
||||
request
|
||||
.extensions()
|
||||
.get::<Option<UserData>>()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.email
|
||||
.as_str(),
|
||||
)
|
||||
.fetch_one(&app_state)
|
||||
.await
|
||||
return true;
|
||||
}
|
||||
_ => {
|
||||
// loop through path to find a permission
|
||||
let mut remaining_path = Path::new(path);
|
||||
loop {
|
||||
let query: Result<(String,), _> = sqlx::query_as(r#"select r.item from role_permissions r join user_roles ur on ur.role_id = r.role_id left join users u on u.id = ur.user_id where item = ? and (email = ? or r.role_id = 1)"#)
|
||||
let query: Result<(String,), _> = sqlx::query_as(r#"select r.item from role_permissions r join user_roles ur on ur.role_id = r.role_id left join users u on u.id = ur.user_id where item = ?"#)
|
||||
.bind(remaining_path.to_str().unwrap())
|
||||
.bind(request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email.as_str())
|
||||
.fetch_one(&app_state)
|
||||
.fetch_one(&db_pool)
|
||||
.await;
|
||||
if let Ok(query) = query {
|
||||
if query.0 != "" {
|
||||
println!("check_auth : found auth for {}", query.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -138,40 +95,19 @@ pub async fn check_auth(
|
|||
}
|
||||
remaining_path = remaining_path.parent().unwrap();
|
||||
}
|
||||
sqlx::query_as(r#"select u.id from role_permissions r join user_roles ur on ur.role_id = r.role_id join users u on u.id = ur.user_id where item = ? and (email = ? or r.role_id = 1)"#)
|
||||
sqlx::query_as(r#"select u.id from role_permissions r join user_roles ur on ur.role_id = r.role_id join users u on u.id = ur.user_id where item = ? and email = ?"#)
|
||||
.bind(remaining_path.to_str().unwrap())
|
||||
.bind(request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email.as_str())
|
||||
.fetch_one(&app_state)
|
||||
.bind(user_data.email.as_str())
|
||||
.fetch_one(&db_pool)
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
// user is logged in
|
||||
// check if user has the proper role
|
||||
// if not, display banner and return to home page
|
||||
let user_id = if let Ok(query) = query {
|
||||
query.0
|
||||
} else {
|
||||
// user does not have the proper role
|
||||
0
|
||||
};
|
||||
|
||||
println!("check_auth : Authenticated user {}", user_id);
|
||||
if user_id == 0 {
|
||||
// user does not have the proper role
|
||||
// display banner and return to home page
|
||||
return Ok(Redirect::to("/").into_response());
|
||||
if let Ok(query) = query {
|
||||
if query.0 == user_data.id {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(next.run(request).await)
|
||||
} else {
|
||||
// user is not logged in
|
||||
// redirect to login page with return_url
|
||||
//let login_url = "/login?return_url=".to_owned() + &*request.uri().to_string();
|
||||
//let login_url = "/login".to_owned();
|
||||
//Ok(Redirect::to(login_url.as_str()).into_response())
|
||||
//println!("check_auth : {:#?}", request.headers().get("referer").unwrap());
|
||||
println!("check_auth : No user data in the request");
|
||||
Ok(next.run(request).await)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
use askama_axum::{Response, Template};
|
||||
use axum::{extract::{Path, State}, response::{Html, IntoResponse}, Extension};
|
||||
use axum::{extract::{Path, State}, response::{Html, IntoResponse, Redirect}, Extension};
|
||||
use http::StatusCode;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::UserData;
|
||||
use crate::{middlewares::is_authorized, UserData};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "profile.html")]
|
||||
|
|
@ -46,44 +46,57 @@ struct DashboardTemplate {
|
|||
}
|
||||
|
||||
pub async fn index(
|
||||
State(db_pool): State<SqlitePool>,
|
||||
Extension(user_data): Extension<Option<UserData>>,
|
||||
) -> impl IntoResponse {
|
||||
let user_name = user_data.map(|s| s.name);
|
||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||
let logged_in = user_name.is_some();
|
||||
let name = user_name.unwrap_or_default();
|
||||
|
||||
println!("index : logged_in = {}, name = {}", logged_in, name);
|
||||
|
||||
let template = IndexTemplate { logged_in, name };
|
||||
HtmlTemplate(template)
|
||||
if is_authorized("/dashboard", user_data, db_pool).await {
|
||||
Redirect::to("/dashboard").into_response()
|
||||
} else {
|
||||
let template = IndexTemplate { logged_in, name };
|
||||
HtmlTemplate(template).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn dashboard(
|
||||
State(db_pool): State<SqlitePool>,
|
||||
Extension(user_data): Extension<Option<UserData>>,
|
||||
) -> impl IntoResponse {
|
||||
let user_name = user_data.map(|s| s.name);
|
||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||
let logged_in = user_name.is_some();
|
||||
let name = user_name.unwrap_or_default();
|
||||
|
||||
let template = DashboardTemplate { logged_in, name};
|
||||
HtmlTemplate(template)
|
||||
if is_authorized("/dashboard", user_data, db_pool).await {
|
||||
let template = DashboardTemplate { logged_in, name};
|
||||
HtmlTemplate(template).into_response()
|
||||
} else {
|
||||
Redirect::to("/").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the profile page.
|
||||
pub async fn profile(
|
||||
State(db_pool): State<SqlitePool>,
|
||||
Extension(user_data): Extension<Option<UserData>>,
|
||||
) -> impl IntoResponse {
|
||||
// Extract the user's name from the user data.
|
||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||
let logged_in = user_data.is_some();
|
||||
let logged_in = user_name.is_some();
|
||||
let name = user_name.unwrap_or_default();
|
||||
|
||||
// Extract the user data.
|
||||
let user = user_data.as_ref().unwrap();
|
||||
let user = user_data.as_ref().unwrap().clone();
|
||||
|
||||
// Create the profile template.
|
||||
let template = ProfileTemplate { logged_in, name, user: user.clone() };
|
||||
return HtmlTemplate(template)
|
||||
if is_authorized("/profile", user_data, db_pool).await {
|
||||
// Create the profile template.
|
||||
let template = ProfileTemplate { logged_in, name, user: user.clone() };
|
||||
return HtmlTemplate(template).into_response()
|
||||
} else {
|
||||
Redirect::to("/").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn user_profile(
|
||||
|
|
@ -106,9 +119,13 @@ pub async fn profile(
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
// Create the profile template.
|
||||
let template = ProfileTemplate { logged_in, name, user: user };
|
||||
return HtmlTemplate(template)
|
||||
if is_authorized("/users", user_data, db_pool).await {
|
||||
// Create the profile template.
|
||||
let template = ProfileTemplate { logged_in, name, user: user };
|
||||
return HtmlTemplate(template).into_response()
|
||||
} else {
|
||||
Redirect::to("/").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
|
|
@ -124,17 +141,21 @@ pub async fn useradmin(
|
|||
State(db_pool): State<SqlitePool>,
|
||||
) -> impl IntoResponse {
|
||||
|
||||
let user_email = user_data.map(|s| s.email);
|
||||
let logged_in = user_email.is_some();
|
||||
let name = user_email.unwrap_or_default();
|
||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||
let logged_in = user_name.is_some();
|
||||
let name = user_name.unwrap_or_default();
|
||||
|
||||
let users = sqlx::query_as::<_, UserData>("SELECT * FROM users")
|
||||
.fetch_all(&db_pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let template = UserAdminTemplate { logged_in, name, users };
|
||||
HtmlTemplate(template)
|
||||
if is_authorized("/useradmin", user_data, db_pool).await {
|
||||
let template = UserAdminTemplate { logged_in, name, users };
|
||||
HtmlTemplate(template).into_response()
|
||||
} else {
|
||||
Redirect::to("/").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
{% block content %}
|
||||
{% if logged_in %}
|
||||
<!-- Redirect to dashboard -->
|
||||
<script>
|
||||
window.location.href = "/dashboard";
|
||||
</script>
|
||||
<!-- Only if user account is authorized -->
|
||||
<h2>Your account has not yet been verified</h2>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
<!-- Carousel -->
|
||||
<div id="demo" class="carousel slide" data-bs-ride="carousel">
|
||||
|
||||
|
|
@ -50,5 +50,4 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
Loading…
Reference in New Issue