jean-marie/backend/KioskNotes.txt

190 lines
4.9 KiB
Plaintext

For a kiosk machine that needs to always auto-login, here's the most practical approach for your Rust/Axum stack:
## Recommended Solution: Device-Specific Token Authentication
### 1. Database Schema
```sql
-- Add to your PostgreSQL database
CREATE TABLE kiosk_devices (
id SERIAL PRIMARY KEY,
device_name VARCHAR(255) NOT NULL,
device_token VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_accessed TIMESTAMP,
is_active BOOLEAN DEFAULT true
);
```
### 2. Axum Route Handler
```rust
use axum::{
extract::{Query, State},
response::{Html, Redirect},
http::StatusCode,
};
use serde::Deserialize;
#[derive(Deserialize)]
struct AutoLoginQuery {
token: String,
}
async fn auto_login(
Query(params): Query<AutoLoginQuery>,
State(app_state): State<AppState>, // Your app state with DB pool
) -> Result<Redirect, StatusCode> {
// Validate the device token
let device = sqlx::query!(
"SELECT id, device_name FROM kiosk_devices
WHERE device_token = $1 AND is_active = true",
params.token
)
.fetch_optional(&app_state.db)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
match device {
Some(device) => {
// Update last accessed
sqlx::query!(
"UPDATE kiosk_devices SET last_accessed = CURRENT_TIMESTAMP WHERE id = $1",
device.id
)
.execute(&app_state.db)
.await
.ok();
// Set session/cookie and redirect to dashboard
Ok(Redirect::to("/kiosk-dashboard"))
}
None => Err(StatusCode::UNAUTHORIZED),
}
}
```
### 3. Generate Device Token
```rust
use uuid::Uuid;
use sha2::{Sha256, Digest};
fn generate_device_token() -> String {
let uuid = Uuid::new_v4();
let mut hasher = Sha256::new();
hasher.update(uuid.as_bytes());
format!("{:x}", hasher.finalize())[..32].to_string()
}
// Store this in your database for the kiosk
async fn register_kiosk_device(db: &PgPool, device_name: &str) -> Result<String, sqlx::Error> {
let token = generate_device_token();
sqlx::query!(
"INSERT INTO kiosk_devices (device_name, device_token) VALUES ($1, $2)",
device_name,
token
)
.execute(db)
.await?;
Ok(token)
}
```
### 4. Kiosk Setup
Configure the kiosk machine to:
**Option A: Browser Homepage**
Set browser homepage to: `https://yoursite.com/auto-login?token=YOUR_GENERATED_TOKEN`
**Option B: Desktop Shortcut**
Create a desktop shortcut with the auto-login URL
**Option C: Startup Script**
```bash
#!/bin/bash
# startup.sh - runs on boot
sleep 10 # wait for network
chromium-browser --kiosk --no-sandbox "https://yoursite.com/auto-login?token=YOUR_TOKEN"
```
### 5. Enhanced Security (Optional)
If you want additional security:
```rust
#[derive(Deserialize)]
struct AutoLoginQuery {
token: String,
timestamp: Option<i64>,
signature: Option<String>,
}
async fn auto_login_with_signature(
Query(params): Query<AutoLoginQuery>,
// ... other params
) -> Result<Redirect, StatusCode> {
// Verify timestamp (within 5 minutes)
if let (Some(timestamp), Some(signature)) = (params.timestamp, params.signature) {
let now = chrono::Utc::now().timestamp();
if (now - timestamp).abs() > 300 { // 5 minutes
return Err(StatusCode::UNAUTHORIZED);
}
// Verify signature (HMAC with shared secret)
let expected_sig = create_signature(&params.token, timestamp);
if signature != expected_sig {
return Err(StatusCode::UNAUTHORIZED);
}
}
// ... rest of validation
}
```
### 6. Session Management
After successful auto-login, set a session cookie:
```rust
use tower_cookies::{Cookie, Cookies};
async fn auto_login(
Query(params): Query<AutoLoginQuery>,
cookies: Cookies,
// ... other params
) -> Result<Redirect, StatusCode> {
// ... validation logic ...
if let Some(device) = device {
// Set session cookie
let session_cookie = Cookie::build(("kiosk_session", device.id.to_string()))
.path("/")
.http_only(true)
.max_age(time::Duration::hours(24))
.build();
cookies.add(session_cookie);
Ok(Redirect::to("/kiosk-dashboard"))
} else {
Err(StatusCode::UNAUTHORIZED)
}
}
```
### 7. Route Configuration
```rust
let app = Router::new()
.route("/auto-login", get(auto_login))
.route("/kiosk-dashboard", get(kiosk_dashboard))
// ... other routes
.layer(CookieManagerLayer::new())
.with_state(app_state);
```
This approach gives you:
- Secure device authentication
- Easy kiosk setup
- Audit trail of access
- Ability to revoke access
- No user interaction required
The kiosk will automatically authenticate and access your application whenever it starts up or navigates to the URL.