313 lines
8.0 KiB
Markdown
313 lines
8.0 KiB
Markdown
# Login System Documentation
|
|
|
|
## Overview
|
|
A complete authentication system for the CGW Product Finder that integrates with the user management system. Users must log in with their credentials to access the product finder application.
|
|
|
|
## Features
|
|
|
|
### 🔐 Secure Authentication
|
|
- Password verification using PBKDF2-SHA256 hashing
|
|
- Session-based authentication with HTTP-only cookies
|
|
- Automatic session management
|
|
- Active/inactive user account checking
|
|
|
|
### 📍 Multi-Location Support
|
|
- Automatic location selection for single-location users
|
|
- Location selection page for users with multiple accessible locations
|
|
- Default location preference
|
|
- Location-based access control
|
|
|
|
### 🛡️ Security Features
|
|
- Login required decorator protects all main routes
|
|
- Inactive accounts are automatically blocked
|
|
- Sessions expire on logout or server restart
|
|
- Secure session cookies (HTTP-only, SameSite)
|
|
|
|
## User Flow
|
|
|
|
### 1. Login Process
|
|
1. User visits the app → Redirected to `/login`
|
|
2. User enters **username** and **password**
|
|
3. System validates credentials against `users.json`
|
|
4. System checks if user account is **active**
|
|
5. If valid and active:
|
|
- Session is created
|
|
- User accessible locations are loaded
|
|
|
|
### 2. Location Selection (if applicable)
|
|
- **Single Accessible Location**: User goes directly to main app (location selection bypassed)
|
|
- **Multiple Accessible Locations**: User is redirected to `/select-location`
|
|
- Shows all accessible locations
|
|
- Default location is pre-selected
|
|
- User can choose their working location
|
|
- Selection is saved to session
|
|
- **Note**: Default location is automatically marked as accessible when user is created
|
|
|
|
### 3. Main Application Access
|
|
- User accesses the Product Finder
|
|
- User info displayed in header (username + current location)
|
|
- Logout button available in header
|
|
|
|
## Routes
|
|
|
|
### Public Routes (No Login Required)
|
|
- `GET /login` - Login page
|
|
- `POST /api/login` - Login endpoint
|
|
- `GET /users` - User management page
|
|
|
|
### Protected Routes (Login Required)
|
|
- `GET /` - Main product finder app
|
|
- `GET /quiz` - Quiz page (alias for main app)
|
|
- `GET /image-test` - Image generation test page
|
|
- `GET /select-location` - Location selection page
|
|
- `POST /api/select-location` - Set current location
|
|
|
|
### Session Routes
|
|
- `GET /api/session` - Get current session info
|
|
- `POST /api/logout` - Logout and clear session
|
|
|
|
## API Endpoints
|
|
|
|
### POST /api/login
|
|
Authenticate user and create session.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"username": "john_doe",
|
|
"password": "password123"
|
|
}
|
|
```
|
|
|
|
**Success Response:**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Login successful",
|
|
"requiresLocationSelection": true
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"message": "Invalid username or password"
|
|
}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"message": "Account is inactive. Please contact an administrator."
|
|
}
|
|
```
|
|
|
|
### GET /api/session
|
|
Get current user session information.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"username": "john_doe",
|
|
"defaultLocation": "LINDS",
|
|
"currentLocation": "KC",
|
|
"accessibleLocations": ["LINDS", "KC", "IOLA"]
|
|
}
|
|
```
|
|
|
|
### POST /api/select-location
|
|
Select a location for the current session.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"location": "KC"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Location selected",
|
|
"currentLocation": "KC"
|
|
}
|
|
```
|
|
|
|
### POST /api/logout
|
|
Log out and clear session.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Logged out successfully"
|
|
}
|
|
```
|
|
|
|
## Session Data
|
|
|
|
The session stores:
|
|
- `user_id`: Index of user in users.json
|
|
- `username`: Username string
|
|
- `defaultLocation`: User's default location code
|
|
- `currentLocation`: Currently selected location code
|
|
- `accessibleLocations`: Array of location codes user can access
|
|
|
|
## Authentication Decorator
|
|
|
|
The `@login_required` decorator protects routes:
|
|
|
|
```python
|
|
@app.route('/protected-page')
|
|
@login_required
|
|
def protected_page():
|
|
return render_template('protected.html')
|
|
```
|
|
|
|
The decorator:
|
|
1. Checks if user is logged in (has `user_id` in session)
|
|
2. Validates user still exists in users.json
|
|
3. Checks if user account is still active
|
|
4. Redirects to login if any check fails
|
|
|
|
## Getting Current User in Routes
|
|
|
|
```python
|
|
@app.route('/my-route')
|
|
@login_required
|
|
def my_route():
|
|
user = get_current_user()
|
|
username = session.get('username')
|
|
current_location = session.get('currentLocation')
|
|
|
|
# Use user data...
|
|
return render_template('page.html')
|
|
```
|
|
|
|
## Location-Based Access Control
|
|
|
|
Users can only access locations they have permission for:
|
|
|
|
```python
|
|
# In users.json
|
|
{
|
|
"username": "john_doe",
|
|
"locationSettings": {
|
|
"LINDS": { "accessible": true },
|
|
"IOLA": { "accessible": false },
|
|
"KC": { "accessible": true },
|
|
"BMD": { "accessible": false }
|
|
}
|
|
}
|
|
```
|
|
|
|
This user can access:
|
|
- ✅ Lindsborg (LINDS)
|
|
- ✅ KC (KC)
|
|
- ❌ Iola (IOLA)
|
|
- ❌ BMD (BMD)
|
|
|
|
## User Interface Components
|
|
|
|
### Login Page (`/login`)
|
|
- Clean, centered login form
|
|
- Username and password fields
|
|
- Submit button with loading spinner
|
|
- Link to User Management page
|
|
- Error message display
|
|
|
|
### Location Selection Page (`/select-location`)
|
|
- Shows logged-in username
|
|
- Shows default location
|
|
- Radio buttons for each accessible location
|
|
- Default location is pre-selected
|
|
- Continue and Logout buttons
|
|
|
|
### Main App Header
|
|
- User info display: `👤 username | 📍 location`
|
|
- Logout button in header
|
|
- Positioned in top-right corner
|
|
|
|
## Security Considerations
|
|
|
|
### Password Security
|
|
- Passwords are hashed using PBKDF2-SHA256
|
|
- Hashes are never reversed or displayed
|
|
- Hash verification happens server-side only
|
|
|
|
### Session Security
|
|
- Sessions use secure random keys
|
|
- Cookies are HTTP-only (not accessible via JavaScript)
|
|
- SameSite cookie policy prevents CSRF attacks
|
|
- Sessions cleared on logout
|
|
|
|
### Account Status
|
|
- Inactive accounts cannot log in
|
|
- If account is deactivated while logged in, next request will log them out
|
|
- User must have at least one accessible location
|
|
|
|
## Testing the Login System
|
|
|
|
### Test User Creation
|
|
1. Go to `/users`
|
|
2. Create a test user:
|
|
- Username: `testuser`
|
|
- Password: `password123`
|
|
- Default Location: Lindsborg
|
|
- Check "Accessible" for Lindsborg and KC
|
|
|
|
### Test Login Flow
|
|
1. Go to `/` (should redirect to `/login`)
|
|
2. Enter credentials: `testuser` / `password123`
|
|
3. Click "Sign In"
|
|
4. Since user has 2 accessible locations → redirected to `/select-location`
|
|
5. Choose a location and click "Continue"
|
|
6. Now viewing main Product Finder app
|
|
7. See user info in header
|
|
8. Click "Logout" to end session
|
|
|
|
### Test Single Location User
|
|
1. Create user with only 1 accessible location
|
|
2. Log in
|
|
3. Should go directly to main app (skip location selection)
|
|
|
|
### Test Inactive User
|
|
1. Create and log in as a user
|
|
2. In User Management, toggle user to "Inactive"
|
|
3. Try to log in → Should see "Account is inactive" message
|
|
|
|
## Troubleshooting
|
|
|
|
### "Please log in first" on all pages
|
|
- Session may have expired
|
|
- Server may have restarted (sessions are in-memory)
|
|
- Clear browser cookies and log in again
|
|
|
|
### "User not found" error
|
|
- User may have been deleted while logged in
|
|
- Log out and log back in
|
|
|
|
### Can't access certain locations
|
|
- Check user's "Accessible" checkboxes in User Management
|
|
- User must have at least one accessible location
|
|
|
|
### Stuck on location selection page
|
|
- User must have multiple accessible locations
|
|
- If this shouldn't happen, check user's location settings
|
|
- Or click "Sign Out" and contact administrator
|
|
|
|
## Future Enhancements
|
|
|
|
Potential additions:
|
|
- [ ] Remember me checkbox (persistent sessions)
|
|
- [ ] Password reset functionality
|
|
- [ ] Session timeout after inactivity
|
|
- [ ] Login attempt limiting (brute force protection)
|
|
- [ ] Two-factor authentication
|
|
- [ ] Session management dashboard
|
|
- [ ] Location switching without re-login
|
|
- [ ] Audit log of login attempts
|