sf-auth-middleware-axum/examples/basic.rs

144 lines
5.2 KiB
Rust

use axum::{middleware, response::Html, routing::get, Router};
use sf_auth_middleware_axum::{auth_callback, sf_auth_middleware, SfAuthConfig, SfUser};
use tower_sessions::{MemoryStore, SessionManagerLayer};
#[tokio::main]
async fn main() {
// Set up tracing for debugging
tracing_subscriber::fmt::init();
// Configure the SF authentication middleware
// The redirect_uri should point to where users should land after authentication
let config = SfAuthConfig::new("http://localhost:3000/dashboard");
// Set up session store using in-memory storage
// In production, you'd want to use a persistent store like Redis or PostgreSQL
let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store);
// Build the application router
let app = Router::new()
// Public route - no authentication required
.route("/", get(home))
// Authentication callback route - must be publicly accessible
// This is where the SF auth server redirects users after authentication
.route("/auth/callback", get(auth_callback))
// Protected routes - require authentication
.route("/dashboard", get(dashboard))
.route("/profile", get(profile))
// Apply authentication middleware to protected routes
.layer(middleware::from_fn(move |session, req, next| {
sf_auth_middleware(config.clone(), session, req, next)
}))
// Apply session layer (must be after the routes)
.layer(session_layer);
// Start the server
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
println!("Server running on http://localhost:3000");
println!("Try accessing:");
println!(" - http://localhost:3000/ (public)");
println!(" - http://localhost:3000/dashboard (protected, will redirect to SF auth)");
println!(" - http://localhost:3000/profile (protected, will redirect to SF auth)");
axum::serve(listener, app).await.unwrap();
}
/// Public home page
async fn home() -> Html<&'static str> {
Html(
r#"
<!DOCTYPE html>
<html>
<head>
<title>SF Auth Example</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
a { color: #0066cc; text-decoration: none; }
a:hover { text-decoration: underline; }
.button {
display: inline-block;
padding: 10px 20px;
background: #0066cc;
color: white;
border-radius: 4px;
margin: 10px 5px;
}
.button:hover { background: #0052a3; text-decoration: none; }
</style>
</head>
<body>
<h1>Welcome to SF Auth Example</h1>
<p>This is a public page that anyone can access.</p>
<p>Try accessing protected pages:</p>
<a href="/dashboard" class="button">Go to Dashboard (Protected)</a>
<a href="/profile" class="button">Go to Profile (Protected)</a>
<p>When you try to access a protected page, you'll be redirected to the SnazzyFellas authentication server.</p>
</body>
</html>
"#,
)
}
/// Protected dashboard page
async fn dashboard(user: SfUser) -> Html<String> {
Html(format!(
r#"
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<style>
body {{ font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }}
.user-info {{ background: #f0f0f0; padding: 15px; border-radius: 4px; margin: 20px 0; }}
a {{ color: #0066cc; }}
</style>
</head>
<body>
<h1>Dashboard</h1>
<div class="user-info">
<h2>Authenticated User</h2>
<p><strong>Username:</strong> {}</p>
<p><strong>User ID:</strong> {}</p>
</div>
<p><a href="/">Back to Home</a> | <a href="/profile">View Profile</a></p>
</body>
</html>
"#,
user.username(),
user.user_id()
))
}
/// Protected profile page
async fn profile(user: SfUser) -> Html<String> {
Html(format!(
r#"
<!DOCTYPE html>
<html>
<head>
<title>Profile</title>
<style>
body {{ font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }}
.profile {{ background: #e8f4f8; padding: 20px; border-radius: 4px; margin: 20px 0; }}
a {{ color: #0066cc; }}
</style>
</head>
<body>
<h1>User Profile</h1>
<div class="profile">
<h2>{}</h2>
<p><strong>ID:</strong> {}</p>
<p>This is your protected profile page.</p>
</div>
<p><a href="/">Back to Home</a> | <a href="/dashboard">View Dashboard</a></p>
</body>
</html>
"#,
user.username(),
user.user_id()
))
}