🔧 Update Admin Dashboard and Authentication Flow
✅ Updated Admin Dashboard URL: - Changed the Admin Dashboard access path from `/admin` to `/manage` in multiple files for consistency. ✅ Enhanced Middleware Authentication: - Updated middleware to protect new admin routes including `/manage` and `/dashboard`. ✅ Implemented CSRF Protection: - Added CSRF token generation and validation for login and session validation routes. ✅ Introduced Rate Limiting: - Added rate limiting for admin routes and CSRF token requests to enhance security. ✅ Refactored Admin Page: - Created a new admin management page with improved authentication handling and user feedback. 🎯 Overall Improvements: - Strengthened security measures for admin access. - Improved user experience with clearer navigation and feedback. - Streamlined authentication processes for better performance.
This commit is contained in:
74
lib/auth.ts
Normal file
74
lib/auth.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
// Server-side authentication utilities
|
||||
export function verifyAdminAuth(request: NextRequest): boolean {
|
||||
// Check for basic auth header
|
||||
const authHeader = request.headers.get('authorization');
|
||||
|
||||
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const base64Credentials = authHeader.split(' ')[1];
|
||||
const credentials = atob(base64Credentials);
|
||||
const [username, password] = credentials.split(':');
|
||||
|
||||
// Get admin credentials from environment
|
||||
const adminAuth = process.env.ADMIN_BASIC_AUTH || 'admin:default_password_change_me';
|
||||
const [expectedUsername, expectedPassword] = adminAuth.split(':');
|
||||
|
||||
return username === expectedUsername && password === expectedPassword;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function requireAdminAuth(request: NextRequest): Response | null {
|
||||
if (!verifyAdminAuth(request)) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Unauthorized' }),
|
||||
{
|
||||
status: 401,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'WWW-Authenticate': 'Basic realm="Admin Access"'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Rate limiting for admin endpoints
|
||||
const rateLimitMap = new Map<string, { count: number; resetTime: number }>();
|
||||
|
||||
export function checkRateLimit(ip: string, maxRequests: number = 10, windowMs: number = 60000): boolean {
|
||||
const now = Date.now();
|
||||
const key = `admin_${ip}`;
|
||||
|
||||
const current = rateLimitMap.get(key);
|
||||
|
||||
if (!current || now > current.resetTime) {
|
||||
rateLimitMap.set(key, { count: 1, resetTime: now + windowMs });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (current.count >= maxRequests) {
|
||||
return false;
|
||||
}
|
||||
|
||||
current.count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getRateLimitHeaders(ip: string, maxRequests: number = 10, windowMs: number = 60000): Record<string, string> {
|
||||
const current = rateLimitMap.get(`admin_${ip}`);
|
||||
const remaining = current ? Math.max(0, maxRequests - current.count) : maxRequests;
|
||||
|
||||
return {
|
||||
'X-RateLimit-Limit': maxRequests.toString(),
|
||||
'X-RateLimit-Remaining': remaining.toString(),
|
||||
'X-RateLimit-Reset': current ? Math.ceil(current.resetTime / 1000).toString() : Math.ceil((Date.now() + windowMs) / 1000).toString()
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user