Files
Sdf1_login/api/security_alert.php
T
ypsdf1 ae1ff5ffd8 异地登录检测/账号冻结解冻 + 公共邮件辅助函数
- core.php: 新增smtpSendEmail/queryLoginIpLocation/getBaseUrl/sendLocationAlertEmail
- security_alert.php: 接收Java通知比对IP归属并发送提醒邮件(含冻结/改密链接)
- freeze.php: 验证freeze_token冻结账号并写freeze指令
- sync.php: 冻结账号禁止Web登录; smtpSendEmail上移至core.php统一复用
- reset_password.php: 改密成功后解冻(清frozen+写unfreeze)
2026-07-09 17:09:35 +08:00

95 lines
3.1 KiB
PHP

<?php
/**
* 异地登录检测回调(Java 插件在玩家加入服务器时异步调用)
*
* 调用方式:GET api/security_alert.php
* ?action=login_location_alert&secret=...&name=<玩家>&ip=<登录IP>
*
* 职责:
* 1. 用 ip9.com.cn 查询本次登录 IP 归属
* 2. 与上次登录归属比较,不一致且非首次 → 向绑定邮箱发送提醒邮件
* 3. 邮件内含「冻结账号」与「修改密码」两个链接
* 4. 更新 users.last_login_location / last_login_ip
*/
require_once __DIR__ . '/../core.php';
header('Content-Type: application/json; charset=utf-8');
$action = $_GET['action'] ?? '';
if ($action !== 'login_location_alert') {
echo json_encode(['success' => false, 'message' => '未知操作']);
exit;
}
$secret = $_GET['secret'] ?? '';
if (!$secret || $secret !== SECRET_KEY) {
echo json_encode(['success' => false, 'message' => '密钥错误']);
exit;
}
$name = $_GET['name'] ?? '';
$ip = $_GET['ip'] ?? '';
if (!$name || !$ip) {
echo json_encode(['success' => false, 'message' => '参数缺失']);
exit;
}
$db = getDB();
// 查询账号信息
$stmt = $db->prepare(
"SELECT email, last_login_location, last_login_ip, frozen
FROM users WHERE player_name = :name");
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
$row = $stmt->execute()->fetchArray(SQLITE3_ASSOC);
// 查询本次 IP 归属
$location = queryLoginIpLocation($ip);
if ($location === null) {
// 归属查询失败:仅更新 IP,不阻断、不提醒
$upd = $db->prepare(
"UPDATE users SET last_login_ip = :ip WHERE player_name = :name");
$upd->bindValue(':ip', $ip, SQLITE3_TEXT);
$upd->bindValue(':name', $name, SQLITE3_TEXT);
$upd->execute();
echo json_encode(['success' => true, 'message' => 'IP归属查询失败,仅更新IP']);
exit;
}
if (!$row) {
// 理论上 Java 已 syncUserOnJoin,不会走到这里
echo json_encode(['success' => true, 'message' => '无用户记录']);
exit;
}
$lastLoc = $row['last_login_location'] ?? '';
$lastIp = $row['last_login_ip'] ?? '';
$email = $row['email'] ?? '';
// 更新归属与 IP
$upd = $db->prepare(
"UPDATE users SET last_login_ip = :ip,
last_login_location = :loc WHERE player_name = :name");
$upd->bindValue(':ip', $ip, SQLITE3_TEXT);
$upd->bindValue(':loc', $location, SQLITE3_TEXT);
$upd->bindValue(':name', $name, SQLITE3_TEXT);
$upd->execute();
// 首次登录(无任何历史记录)不提醒
if ($lastLoc === '' && $lastIp === '') {
echo json_encode(['success' => true, 'message' => '首次登录,已记录']);
exit;
}
// 归属变化才发送提醒邮件
if ($lastLoc !== $location && !empty($email)) {
// 生成冻结 token 并持久化,供邮件中的冻结链接使用
$freezeToken = bin2hex(random_bytes(16));
$ut = $db->prepare("UPDATE users SET freeze_token = :t WHERE player_name = :name");
$ut->bindValue(':t', $freezeToken, SQLITE3_TEXT);
$ut->bindValue(':name', $name, SQLITE3_TEXT);
$ut->execute();
sendLocationAlertEmail($name, $email, $ip, $location, $lastLoc, $freezeToken);
}
echo json_encode(['success' => true, 'message' => 'ok']);