<?php
class AuthenticationServer { private $db; private $sessionManager; private $rateLimiter; public function __construct() { $this->db = new PDO('mysql:host=localhost;dbname=captive_portal', 'username', 'password'); $this->sessionManager = new SessionManager(); $this->rateLimiter = new RateLimiter(); }
public function handlePortalRequest($request) { $clientInfo = $request->getClientInfo(); if ($this->isAlreadyAuthenticated($clientInfo['mac'])) { return $this->redirectToInternet(); } return $this->renderAuthPage($clientInfo); }
private function renderAuthPage($clientInfo) { $html = <<<HTML <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>WiFi认证 - {$clientInfo['ssid']}</title> <style> body { font-family: Arial, sans-serif; max-width: 400px; margin: 50px auto; padding: 20px; } .container { border: 1px solid #ddd; padding: 20px; border-radius: 5px; } input, button { width: 100%; padding: 10px; margin: 10px 0; } .countdown { color: #666; font-size: 12px; } .agreement { font-size: 12px; color: #666; margin: 10px 0; } </style> </head> <body> <div class="container"> <h2>欢迎使用 {$clientInfo['ssid']} WiFi</h2> <p>请输入手机号获取验证码进行认证</p> <div id="step1"> <input type="tel" id="phone" placeholder="请输入手机号码" maxlength="11"> <button onclick="sendCode()" id="sendBtn">获取验证码</button> <div class="countdown" id="countdown" style="display:none;"></div> <div class="agreement"> <input type="checkbox" id="agree" checked> 我已阅读并同意 <a href="/terms" target="_blank">《服务协议》</a> 和 <a href="/privacy" target="_blank">《隐私政策》</a> </div> </div> <div id="step2" style="display:none;"> <input type="text" id="code" placeholder="请输入6位验证码" maxlength="6"> <button onclick="verifyCode()">连接网络</button> </div> <input type="hidden" id="client_mac" value="{$clientInfo['mac']}"> <input type="hidden" id="client_ip" value="{$clientInfo['ip']}"> <div id="message" style="color:red; margin-top:10px;"></div> </div> <script> let countdownTime = 60; let countdownInterval; function sendCode() { const phone = document.getElementById('phone').value; const agree = document.getElementById('agree').checked; if (!/^1[3-9]\d{9}$/.test(phone)) { showMessage('请输入有效的手机号码'); return; } if (!agree) { showMessage('请同意服务协议和隐私政策'); return; } // 发送验证码请求 fetch('/api/send-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: phone, client_mac: document.getElementById('client_mac').value, client_ip: document.getElementById('client_ip').value }) }) .then(response => response.json()) .then(data => { if (data.success) { showMessage('验证码已发送'); document.getElementById('step1').style.display = 'none'; document.getElementById('step2').style.display = 'block'; startCountdown(); } else { showMessage(data.message || '发送失败'); } }); } function verifyCode() { const phone = document.getElementById('phone').value; const code = document.getElementById('code').value; fetch('/api/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: phone, code: code, client_mac: document.getElementById('client_mac').value, client_ip: document.getElementById('client_ip').value }) }) .then(response => response.json()) .then(data => { if (data.success) { showMessage('认证成功,正在连接网络...', 'green'); setTimeout(() => { window.location.href = data.redirect_url || 'http://www.example.com'; }, 2000); } else { showMessage(data.message || '验证失败'); } }); } function startCountdown() { const btn = document.getElementById('sendBtn'); const countdownEl = document.getElementById('countdown'); btn.disabled = true; countdownEl.style.display = 'block'; countdownInterval = setInterval(() => { countdownTime--; countdownEl.textContent = `${countdownTime}秒后可重新发送`; if (countdownTime <= 0) { clearInterval(countdownInterval); btn.disabled = false; countdownEl.style.display = 'none'; countdownTime = 60; } }, 1000); } function showMessage(msg, color = 'red') { const el = document.getElementById('message'); el.textContent = msg; el.style.color = color; } </script> </body> </html> HTML;
return new HTTPResponse(200, [], $html); }
public function handleSendCodeRequest($request) { $data = $request->getJsonData(); $phone = $data['phone']; $clientMac = $data['client_mac']; if (!$this->rateLimiter->checkLimit($phone, 'send_code', 3, 300)) { return ['success' => false, 'message' => '发送过于频繁,请稍后再试']; } $code = $this->generateVerificationCode(); $stmt = $this->db->prepare(" INSERT INTO verification_codes (phone, code, client_mac, created_at, expires_at) VALUES (?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 10 MINUTE)) "); $stmt->execute([$phone, $code, $clientMac]); $smsResult = $this->sendSMSCode($phone, $code); if ($smsResult) { return ['success' => true, 'message' => '验证码已发送']; } return ['success' => false, 'message' => '短信发送失败']; }
public function handleVerifyRequest($request) { $data = $request->getJsonData(); $phone = $data['phone']; $code = $data['code']; $clientMac = $data['client_mac']; $clientIp = $data['client_ip']; $stmt = $this->db->prepare(" SELECT id FROM verification_codes WHERE phone = ? AND code = ? AND client_mac = ? AND used = 0 AND expires_at > NOW() ORDER BY created_at DESC LIMIT 1 "); $stmt->execute([$phone, $code, $clientMac]); $result = $stmt->fetch(PDO::FETCH_ASSOC); if (!$result) { return ['success' => false, 'message' => '验证码错误或已过期']; } $this->db->prepare("UPDATE verification_codes SET used = 1 WHERE id = ?") ->execute([$result['id']]); $sessionId = $this->sessionManager->createSession([ 'phone' => $phone, 'client_mac' => $clientMac, 'client_ip' => $clientIp, 'authenticated_at' => date('Y-m-d H:i:s') ]); $this->notifyNetworkDevice($clientMac, 'grant_access'); $this->logUserAccess($phone, $clientMac, $clientIp); return [ 'success' => true, 'message' => '认证成功', 'redirect_url' => $this->getRedirectUrl($request), 'session_id' => $sessionId ]; }
private function notifyNetworkDevice($clientMac, $action) { $networkApi = new NetworkDeviceAPI(); $networkApi->updateClientStatus($clientMac, $action); $this->db->prepare(" INSERT INTO client_auth_status (client_mac, action, processed, created_at) VALUES (?, ?, 0, NOW()) ")->execute([$clientMac, $action]); } }
?>
|