重定向实现

This commit is contained in:
yly 2023-10-30 19:02:57 +08:00
parent a9fd136a55
commit 168619ef63
5 changed files with 215 additions and 18 deletions

148
Cargo.lock generated
View File

@ -45,6 +45,58 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "askama"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134"
dependencies = [
"askama_derive",
"askama_escape",
"askama_shared",
]
[[package]]
name = "askama_derive"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522"
dependencies = [
"askama_shared",
"proc-macro2",
"syn 1.0.109",
]
[[package]]
name = "askama_escape"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
[[package]]
name = "askama_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6083ccb191711e9c2b80b22ee24a8381a18524444914c746d4239e21d1afaf"
dependencies = [
"askama_escape",
"humansize",
"nom 6.1.2",
"num-traits",
"percent-encoding",
"proc-macro2",
"quote",
"serde",
"syn 1.0.109",
"toml",
]
[[package]]
name = "async-trait"
version = "0.1.74"
@ -69,7 +121,9 @@ dependencies = [
name = "auth"
version = "0.1.0"
dependencies = [
"askama",
"axum",
"minijinja",
"serde",
"sqlx",
"tokio",
@ -185,6 +239,18 @@ dependencies = [
"serde",
]
[[package]]
name = "bitvec"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@ -415,6 +481,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "funty"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futures-channel"
version = "0.3.29"
@ -657,6 +729,12 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humansize"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
[[package]]
name = "hyper"
version = "0.14.27"
@ -724,6 +802,19 @@ dependencies = [
"spin 0.5.2",
]
[[package]]
name = "lexical-core"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
dependencies = [
"arrayvec",
"bitflags 1.3.2",
"cfg-if",
"ryu",
"static_assertions",
]
[[package]]
name = "libc"
version = "0.2.149"
@ -806,6 +897,15 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minijinja"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f98b09920c8be9ff96a5625aca5b5db7a4f4ba025132ff7d7aacb72c0244a45"
dependencies = [
"serde",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@ -832,6 +932,19 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "nom"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
dependencies = [
"bitvec",
"funty",
"lexical-core",
"memchr",
"version_check",
]
[[package]]
name = "nom"
version = "7.1.3"
@ -1064,6 +1177,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "rand"
version = "0.8.5"
@ -1374,7 +1493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85"
dependencies = [
"itertools",
"nom",
"nom 7.1.3",
"unicode_categories",
]
@ -1572,6 +1691,12 @@ dependencies = [
"url",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stringprep"
version = "0.1.4"
@ -1617,6 +1742,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
version = "3.8.1"
@ -1745,6 +1876,15 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "totp-rs"
version = "5.4.0"
@ -2077,6 +2217,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "wyz"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "zerocopy"
version = "0.7.18"

View File

@ -16,3 +16,5 @@ totp-rs = "5.4.0"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
tower-http = { version = "0.4.4", features = ["trace"] }
tracing = "0.1.40"
askama = "0.10"
minijinja = "1.0.9"

29
auth.conf Normal file
View File

@ -0,0 +1,29 @@
upstream protected {
server 127.0.0.1:10000;
}
server {
listen 8080;
location / {
auth_request /auth;
set $original_full_url $scheme://$host$request_uri;
error_page 401 =200 /login;
proxy_set_header X-Original-URI $scheme://$host$request_uri;
proxy_pass http://protected/;
}
location = /auth {
internal;
proxy_pass http://localhost:3000/auth;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri; #可用来控制权限
proxy_set_header X-Original-Remote-Addr $remote_addr;
proxy_set_header X-Original-Host $host;
}
location /login {
proxy_pass http://localhost:3000/login;
proxy_set_header X-Original-Remote-Addr $remote_addr;
proxy_set_header X-Original-Host $host;
proxy_set_header X-Original-URI $original_full_url;
}
}

View File

@ -53,13 +53,11 @@
<body>
<div class="container">
<h1>Login</h1>
<form action="/login" method="POST">
<form action="/login{{ url }}" method="POST">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="otp" required>
<input type="submit" value="Submit">
</form>
</div>

View File

@ -1,4 +1,4 @@
use axum::{Extension, TypedHeader};
use axum::extract::Query;
use axum::response::{Html, Redirect};
use axum::http::{Uri, HeaderMap, HeaderValue};
use axum::{
@ -20,6 +20,7 @@ use tower_cookies::{Cookie, CookieManagerLayer, Cookies};
use uuid::Uuid;
use tower_http::trace::{self, TraceLayer};
use tracing::Level;
use minijinja::{Environment, context};
pub struct ServerState {
pub db: sqlx::Pool<sqlx::Sqlite>,
pub session: Mutex<HashMap<Uuid, Instant>>,
@ -88,10 +89,12 @@ async fn auth(
cookies: Cookies,
) -> StatusCode {
if let Some(session_token) = cookies.get(COOKIE_NAME) {
tracing::info!("session:{}",session_token.value());
let Ok(s) = uuid::Uuid::from_str(session_token.value()) else {
return StatusCode::UNAUTHORIZED;
};
let mut locked = state.session.lock().await;
if locked.contains_key(&s) { // FIX
let Some(v) = locked.insert(s,Instant::now()+Duration::from_secs(SESSION_ACTIVE_TIME)) else {
return StatusCode::UNAUTHORIZED;
};
@ -99,18 +102,19 @@ async fn auth(
return StatusCode::OK;
}
}
}
return StatusCode::UNAUTHORIZED;
}
async fn login(
State(state): State<Arc<ServerState>>,
cookies: Cookies,
headers: HeaderMap<HeaderValue>,
Query(mut params): Query<HashMap<String, String>>,
Form(frm): Form<UserLoginForm>,
) -> impl IntoResponse {
) -> Result<Redirect, (StatusCode, &'static str)> {
let conn = state.db.acquire().await;
let Ok(mut conn) = conn else {
return (StatusCode::BAD_GATEWAY, "db连接错误");
return Err((StatusCode::BAD_GATEWAY, "db连接错误"));
};
tracing::info!("{:?}",&frm);
let target = sqlx::query_as::<_, UserLoginForm>(
@ -129,17 +133,35 @@ SELECT NAME, KEY FROM USERS WHERE NAME = ?
let mut locked = state.session.lock().await;
locked.insert(s.clone(), Instant::now() + Duration::from_secs(SESSION_ACTIVE_TIME));
cookies.add(Cookie::new(COOKIE_NAME, s.to_string()));
return (StatusCode::ACCEPTED, "ok");
if let Some(original_uri) = params.get("original_url") {
return Ok(Redirect::permanent(&original_uri));
}
return Err((StatusCode::ACCEPTED, "ok"));
} else {
return (StatusCode::UNAUTHORIZED,"wrong password");
return Err((StatusCode::UNAUTHORIZED,"wrong password"));
}
}
return (StatusCode::BAD_GATEWAY, "unreachable");
return Err((StatusCode::BAD_GATEWAY, "unreachable"));
}
async fn login_page(
headers: HeaderMap<HeaderValue>,
)-> impl IntoResponse{
return Html(LOGIN_PAGE_HTML);
tracing::info!("Headers: {:#?}",headers);
let mut env = Environment::new();
env.add_template("login.html", LOGIN_PAGE_HTML).unwrap();
let template = env.get_template("login.html").unwrap();
if let Some(original_uri) = headers.get("X-Original-URI") {
if let Ok(uri) = original_uri.to_str() {
tracing::info!("redirect to {}",uri);
if !uri.is_empty() {
let uri = "?original_url=".to_owned()+uri;
return Html(template.render(context! { url => uri }).unwrap_or("Error".to_string()))
}
}
}
return Html(template.render(context! { url => String::new() }).unwrap_or("Error".to_string()))
}
pub fn check_otp(key_from_db: String, user_input_otp: String) -> bool {