Implement frontend authentication system with login/registration
- Add comprehensive authentication module with mock service - Create login and registration components with form validation - Implement protected routing with yew-router - Add responsive UI styling with gradient design - Enable JWT token persistence via localStorage - Support demo credentials (demo/password) and flexible auth for development 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
123
src/auth.rs
Normal file
123
src/auth.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
// Frontend-only authentication module (simplified for WASM compatibility)
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct User {
|
||||
pub id: String,
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserInfo {
|
||||
pub id: String,
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RegisterRequest {
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LoginRequest {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct AuthResponse {
|
||||
pub token: String,
|
||||
pub user: UserInfo,
|
||||
}
|
||||
|
||||
// Simplified frontend-only auth service
|
||||
pub struct AuthService;
|
||||
|
||||
impl AuthService {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
// Mock authentication methods for development
|
||||
// In production, these would make HTTP requests to a backend API
|
||||
|
||||
pub async fn register(&self, request: RegisterRequest) -> Result<AuthResponse, String> {
|
||||
// Simulate API delay
|
||||
gloo_timers::future::TimeoutFuture::new(500).await;
|
||||
|
||||
// Basic validation
|
||||
if request.username.trim().is_empty() || request.email.trim().is_empty() || request.password.is_empty() {
|
||||
return Err("All fields are required".to_string());
|
||||
}
|
||||
|
||||
if request.password.len() < 6 {
|
||||
return Err("Password must be at least 6 characters".to_string());
|
||||
}
|
||||
|
||||
// Mock successful registration
|
||||
Ok(AuthResponse {
|
||||
token: format!("mock-jwt-token-{}", request.username),
|
||||
user: UserInfo {
|
||||
id: "user-123".to_string(),
|
||||
username: request.username,
|
||||
email: request.email,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn login(&self, request: LoginRequest) -> Result<AuthResponse, String> {
|
||||
// Simulate API delay
|
||||
gloo_timers::future::TimeoutFuture::new(500).await;
|
||||
|
||||
// Basic validation
|
||||
if request.username.trim().is_empty() || request.password.is_empty() {
|
||||
return Err("Username and password are required".to_string());
|
||||
}
|
||||
|
||||
// Mock authentication - accept demo/password or any user/password combo
|
||||
if request.username == "demo" && request.password == "password" {
|
||||
Ok(AuthResponse {
|
||||
token: "mock-jwt-token-demo".to_string(),
|
||||
user: UserInfo {
|
||||
id: "demo-user-123".to_string(),
|
||||
username: request.username,
|
||||
email: "demo@example.com".to_string(),
|
||||
},
|
||||
})
|
||||
} else if !request.password.is_empty() {
|
||||
// Accept any non-empty password for development
|
||||
let username = request.username.clone();
|
||||
Ok(AuthResponse {
|
||||
token: format!("mock-jwt-token-{}", username),
|
||||
user: UserInfo {
|
||||
id: format!("user-{}", username),
|
||||
username: request.username,
|
||||
email: format!("{}@example.com", username),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
Err("Invalid credentials".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn verify_token(&self, token: &str) -> Result<UserInfo, String> {
|
||||
// Simulate API delay
|
||||
gloo_timers::future::TimeoutFuture::new(100).await;
|
||||
|
||||
// Mock token verification
|
||||
if token.starts_with("mock-jwt-token-") {
|
||||
let username = token.strip_prefix("mock-jwt-token-").unwrap_or("unknown");
|
||||
Ok(UserInfo {
|
||||
id: format!("user-{}", username),
|
||||
username: username.to_string(),
|
||||
email: format!("{}@example.com", username),
|
||||
})
|
||||
} else {
|
||||
Err("Invalid token".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user