feat: implement admin login
Implement Story 1.2 (Admin Login) with full TDD approach including: - RateLimit model for tracking authentication attempts - LoginForm for admin authentication with email, password, and remember_me fields - Rate limiting utility functions (check, increment, reset) - admin_required decorator for route protection - Login route with rate limiting (5 attempts per 15 minutes) - Logout route with session clearing - Admin dashboard now requires authentication - Login template with flash message support - 14 comprehensive integration tests covering all acceptance criteria - Email normalization to lowercase - Session persistence with configurable duration (7 or 30 days) All acceptance criteria met: - Login form accepts email and password - Invalid credentials show appropriate error message - Successful login redirects to admin dashboard - Session persists across browser refreshes - Rate limiting after 5 failed attempts Test coverage: 90.67% (exceeds 80% requirement) All linting and type checking passes Story: 1.2 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
"""Decorators for Sneaky Klaus application."""
|
||||
|
||||
from src.decorators.auth import admin_required
|
||||
|
||||
__all__ = ["admin_required"]
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Authentication decorators for route protection."""
|
||||
|
||||
from functools import wraps
|
||||
|
||||
from flask import flash, redirect, session, url_for
|
||||
|
||||
|
||||
def admin_required(f):
|
||||
"""Decorator to require admin authentication for a route.
|
||||
|
||||
Checks if user is logged in as admin. If not, redirects to login page
|
||||
with appropriate flash message.
|
||||
|
||||
Args:
|
||||
f: The function to decorate.
|
||||
|
||||
Returns:
|
||||
Decorated function that checks authentication.
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if "admin_id" not in session:
|
||||
flash("You must be logged in as admin to access this page.", "error")
|
||||
return redirect(url_for("admin.login"))
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
Reference in New Issue
Block a user