wip: work on auth
This commit is contained in:
parent
b029b4b975
commit
c78e386645
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -1872,6 +1872,8 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum 0.7.4",
|
"axum 0.7.4",
|
||||||
|
"axum-login",
|
||||||
|
"axum-messages",
|
||||||
"barrel",
|
"barrel",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
@ -1894,6 +1896,7 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
|
"tower-sessions",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ sea-orm = { version = "0.12.10", features = [
|
|||||||
sqlformat = { version = "0.2.2", optional = true }
|
sqlformat = { version = "0.2.2", optional = true }
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
axum = "0.7"
|
axum = "0.7"
|
||||||
|
axum-login = "0.15.3"
|
||||||
|
axum-messages = "0.6.1"
|
||||||
barrel = { version = "0.7.0", optional = true, features = ["pg"] }
|
barrel = { version = "0.7.0", optional = true, features = ["pg"] }
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
mime_guess = "2.0.4"
|
mime_guess = "2.0.4"
|
||||||
@ -56,3 +58,4 @@ tracing = "0.1.40"
|
|||||||
tower-http = { version = "0.5.1", features = ["trace"] }
|
tower-http = { version = "0.5.1", features = ["trace"] }
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
thiserror = "1.0.61"
|
thiserror = "1.0.61"
|
||||||
|
tower-sessions = { version = "0.12.2" }
|
||||||
|
@ -29,6 +29,10 @@ where
|
|||||||
pub async fn create_tables(db: &DbConn) {
|
pub async fn create_tables(db: &DbConn) {
|
||||||
create_table(db, user::Entity).await;
|
create_table(db, user::Entity).await;
|
||||||
create_table(db, permission::Entity).await;
|
create_table(db, permission::Entity).await;
|
||||||
|
create_table(db, group::Entity).await;
|
||||||
|
create_table(db, user_permission::Entity).await;
|
||||||
|
create_table(db, group_permission::Entity).await;
|
||||||
|
create_table(db, user_group::Entity).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -183,16 +183,16 @@ impl AdminRepository for UserRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(registry: &mut AdminRegistry, db: DatabaseConnection) {
|
pub fn register(registry: &mut AdminRegistry, db: DatabaseConnection) -> UserRepository {
|
||||||
let app_key = registry.register_app("Auth");
|
let app_key = registry.register_app("Auth");
|
||||||
let repo = UserRepository::new(db);
|
let repo = UserRepository::new(db);
|
||||||
let model_config = AdminModelConfig {
|
let model_config = AdminModelConfig {
|
||||||
app_key: app_key,
|
app_key: app_key,
|
||||||
name: "User".to_owned(),
|
name: "User".to_owned(),
|
||||||
};
|
};
|
||||||
let model_result = registry.register_model(model_config, repo);
|
let model_result = registry.register_model(model_config, repo.clone());
|
||||||
match model_result {
|
match model_result {
|
||||||
Err(err) => panic!("{}", err),
|
Err(err) => panic!("{}", err),
|
||||||
_ => (),
|
_ => repo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use axum::{
|
|||||||
Form, Router,
|
Form, Router,
|
||||||
};
|
};
|
||||||
use axum_messages::{Message, Messages};
|
use axum_messages::{Message, Messages};
|
||||||
use rear::service::templates::Templates;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::models::{AuthSession, Credentials};
|
use crate::models::{AuthSession, Credentials};
|
||||||
@ -24,11 +23,12 @@ pub struct NextUrl {
|
|||||||
next: Option<String>,
|
next: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn router() -> Router<Templates> {
|
pub fn routes<S: rear::admin::state::AdminState + Clone + Send + Sync + 'static>() -> Router<S>
|
||||||
|
where {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/login", post(self::post::login))
|
.route("/login", post(self::post::login))
|
||||||
.route("/login", get(self::get::login))
|
.route("/login", get(self::get::login::<S>))
|
||||||
.route("/logout", get(self::get::logout))
|
.route("/logout", post(self::post::logout))
|
||||||
}
|
}
|
||||||
|
|
||||||
mod post {
|
mod post {
|
||||||
@ -44,7 +44,7 @@ mod post {
|
|||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
messages.error("Invalid credentials");
|
messages.error("Invalid credentials");
|
||||||
|
|
||||||
let mut login_url = "/login".to_string();
|
let mut login_url = "/admin/login".to_string();
|
||||||
if let Some(next) = creds.next {
|
if let Some(next) = creds.next {
|
||||||
login_url = format!("{}?next={}", login_url, next);
|
login_url = format!("{}?next={}", login_url, next);
|
||||||
};
|
};
|
||||||
@ -67,23 +67,6 @@ mod post {
|
|||||||
}
|
}
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mod get {
|
|
||||||
use super::*;
|
|
||||||
use axum::extract::State;
|
|
||||||
|
|
||||||
pub async fn login(
|
|
||||||
messages: Messages,
|
|
||||||
templates: State<Templates>,
|
|
||||||
Query(NextUrl { next }): Query<NextUrl>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let context = LoginTemplate {
|
|
||||||
messages: messages.into_iter().collect(),
|
|
||||||
next,
|
|
||||||
};
|
|
||||||
templates.render_html("login.html", context)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn logout(mut auth_session: AuthSession) -> impl IntoResponse {
|
pub async fn logout(mut auth_session: AuthSession) -> impl IntoResponse {
|
||||||
match auth_session.logout().await {
|
match auth_session.logout().await {
|
||||||
@ -93,4 +76,22 @@ mod get {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod get {
|
||||||
|
use super::*;
|
||||||
|
use axum::extract::State;
|
||||||
|
|
||||||
|
pub async fn login<S: rear::admin::state::AdminState + Clone + Send + Sync + 'static>(
|
||||||
|
messages: Messages,
|
||||||
|
admin: State<S>,
|
||||||
|
Query(NextUrl { next }): Query<NextUrl>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let templates = admin.get_templates();
|
||||||
|
let context = LoginTemplate {
|
||||||
|
messages: messages.into_iter().collect(),
|
||||||
|
next,
|
||||||
|
};
|
||||||
|
templates.render_html("admin/login.html", context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this was taken from the axum_login examples and modified. Redirection might need reverse-routing support.
|
// this was taken from the axum_login examples and modified. Redirection might need reverse-routing support.
|
||||||
|
25
src/main.rs
25
src/main.rs
@ -16,6 +16,11 @@ use axum::{
|
|||||||
use axum::{
|
use axum::{
|
||||||
extract::State, handler::HandlerWithoutStateExt, response::IntoResponse, routing::get, Router,
|
extract::State, handler::HandlerWithoutStateExt, response::IntoResponse, routing::get, Router,
|
||||||
};
|
};
|
||||||
|
use axum_login::login_required;
|
||||||
|
use axum_login::tower_sessions::MemoryStore;
|
||||||
|
use axum_login::tower_sessions::SessionManagerLayer;
|
||||||
|
use axum_login::AuthManagerLayerBuilder;
|
||||||
|
use axum_messages::MessagesManagerLayer;
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
use log::info;
|
use log::info;
|
||||||
use rear::admin;
|
use rear::admin;
|
||||||
@ -52,7 +57,7 @@ async fn main() {
|
|||||||
|
|
||||||
// Register Admin Apps
|
// Register Admin Apps
|
||||||
static_repository::register(&mut admin);
|
static_repository::register(&mut admin);
|
||||||
//user_repository::register(&mut admin, db_connection);
|
let admin_user_repo = rear_auth::user_admin_repository::register(&mut admin, db_connection);
|
||||||
file_repository::register(&mut admin, "static/admin");
|
file_repository::register(&mut admin, "static/admin");
|
||||||
|
|
||||||
// Create global Application State.
|
// Create global Application State.
|
||||||
@ -61,12 +66,28 @@ async fn main() {
|
|||||||
admin: Arc::new(admin),
|
admin: Arc::new(admin),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Session System
|
||||||
|
let session_store = MemoryStore::default();
|
||||||
|
let session_layer = SessionManagerLayer::new(session_store);
|
||||||
|
// Auth service.
|
||||||
|
let auth_layer = AuthManagerLayerBuilder::new(admin_user_repo, session_layer).build();
|
||||||
|
|
||||||
// Application Route
|
// Application Route
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(home))
|
.route("/", get(home))
|
||||||
.route("/hello", get(hello_world))
|
.route("/hello", get(hello_world))
|
||||||
//.merge(admin_router)
|
//.merge(admin_router)
|
||||||
.nest("/admin", admin::routes())
|
.nest(
|
||||||
|
"/admin",
|
||||||
|
admin::routes()
|
||||||
|
.route_layer(login_required!(
|
||||||
|
rear_auth::models::UserRepository,
|
||||||
|
login_url = "/admin/login"
|
||||||
|
))
|
||||||
|
.merge(rear_auth::views::routes())
|
||||||
|
.layer(MessagesManagerLayer)
|
||||||
|
.layer(auth_layer),
|
||||||
|
)
|
||||||
.nest("/howto", howto::routes())
|
.nest("/howto", howto::routes())
|
||||||
.route_service("/static/*file", embed::static_handler.into_service())
|
.route_service("/static/*file", embed::static_handler.into_service())
|
||||||
.fallback(handlers::not_found_handler)
|
.fallback(handlers::not_found_handler)
|
||||||
|
43
templates/admin/login.html
Normal file
43
templates/admin/login.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Login</title>
|
||||||
|
<style>
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<ul>
|
||||||
|
{% for message in messages %}
|
||||||
|
<li>
|
||||||
|
<span><strong>{{ message }}</strong></span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>User login</legend>
|
||||||
|
<p>
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input name="username" id="username" value="ferris" />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input name="password" id="password" type="password" value="hunter42" />
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<input type="submit" value="login" />
|
||||||
|
|
||||||
|
{% if next %}
|
||||||
|
<input type="hidden" name="next" value="{{next}}" />
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user