Add login.php

main
p28wg6zfq 1 month ago
parent 1a1ef35b86
commit 94635da63c

@ -0,0 +1,507 @@
<?php
require_once("config.php"); // 数据库连接配置
session_start();
// 反爬机制配置
$antiSpamConfig = [
'login_attempts_limit' => 5, // 登录尝试次数限制
'block_time' => 15 * 60, // 封锁时间(秒)
'check_interval' => 60 * 60, // 检查时间窗口(秒)
'ip_blacklist_file' => __DIR__ . '/data/ip_blacklist.txt',
'login_attempts_file' => __DIR__ . '/data/login_attempts.json'
];
$antiSpamDir = dirname($antiSpamConfig['login_attempts_file']);
if (!file_exists($antiSpamDir)) {
mkdir($antiSpamDir, 0777, true);
}
// 获取客户端IP地址
function getClientIP() {
if (isset($_SERVER['HTTP_CLIENT_IP']))
return $_SERVER['HTTP_CLIENT_IP'];
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
return explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
return $_SERVER['REMOTE_ADDR'];
}
// 检查IP是否在黑名单中
function isIPBlacklisted($ip, $blacklistFile) {
if (!file_exists($blacklistFile)) return false;
$blacklist = file($blacklistFile, FILE_IGNORE_NEW_LINES);
return in_array($ip, $blacklist);
}
// 记录登录尝试
function logLoginAttempt($ip, $success, $config) {
$attempts = [];
$file = $config['login_attempts_file'];
// 读取现有记录
if (file_exists($file)) {
$json = file_get_contents($file);
$attempts = json_decode($json, true) ?: [];
}
// 添加新记录
$attempts[] = [
'ip' => $ip,
'time' => time(),
'success' => $success
];
// 只保留指定时间窗口内的记录
$threshold = time() - $config['check_interval'];
$attempts = array_filter($attempts, function($a) use ($threshold) {
return $a['time'] >= $threshold;
});
// 保存记录
file_put_contents($file, json_encode(array_values($attempts)));
// 如果失败次数超过限制将IP加入黑名单
$ipAttempts = array_filter($attempts, function($a) use ($ip) {
return $a['ip'] === $ip && !$a['success'];
});
if (count($ipAttempts) >= $config['login_attempts_limit']) {
addToIPBlacklist($ip, $config['ip_blacklist_file']);
return true; // IP已被封锁
}
return false;
}
// 添加IP到黑名单
function addToIPBlacklist($ip, $blacklistFile) {
file_put_contents($blacklistFile, $ip . PHP_EOL, FILE_APPEND);
}
// 检查并处理验证码请求
if (isset($_GET['get_captcha'])) {
// 可以添加IP请求频率检查
header('Content-Type: image/png');
include('verify.php');
exit;
}
// 获取客户端IP
$clientIP = getClientIP();
// 检查IP是否被封锁
if (isIPBlacklisted($clientIP, $antiSpamConfig['ip_blacklist_file'])) {
http_response_code(403);
die("您的IP已被封锁请稍后再试。");
}
// 密码哈希加密配置(可选:设置算法参数)
// define('PASSWORD_COST', 12); // 默认10数值越大越安全但性能消耗越高
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = trim($_POST["username"]); // 去除首尾空格
$plainPassword = trim($_POST["pwd"]); // 原始密码(不存储)
$code = trim($_POST["code"]);
// 输入验证:非空检查
if (empty($username) || empty($plainPassword) || empty($code)) {
logLoginAttempt($clientIP, false, $antiSpamConfig);
echo "<script>alert('用户名、密码或验证码不可为空!'); location.href='login.php';</script>";
exit();
}
// 验证码验证区分大小写需调整strtolower
if (strtolower($_SESSION["code"]) !== strtolower($code)) {
logLoginAttempt($clientIP, false, $antiSpamConfig);
echo "<script>alert('验证码错误!请重新登录!'); location.href='login.php';</script>";
exit();
}
// 数据库查询:获取用户哈希密码
$stmt = $connect->prepare("SELECT id, username, password FROM librarian WHERE username=?");
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
if ($user = $result->fetch_assoc()) {
// 验证密码哈希
if (password_verify($plainPassword, $user["password"])) {
// 密码正确,更新会话并跳转
logLoginAttempt($clientIP, true, $antiSpamConfig);
$_SESSION["user_id"] = $user["id"];
$_SESSION["username"] = $user["username"];
$_SESSION["login_time"] = time(); // 记录登录时间(可选)
// 自动更新哈希版本(可选:若使用旧算法)
// if (password_needs_rehash($user["password"], PASSWORD_DEFAULT, ['cost' => PASSWORD_COST])) {
// $newHashedPassword = password_hash($plainPassword, PASSWORD_DEFAULT, ['cost' => PASSWORD_COST]);
// $updateStmt = $connect->prepare("UPDATE librarian SET password=? WHERE id=?");
// $updateStmt->bind_param("si", $newHashedPassword, $user["id"]);
// $updateStmt->execute();
// $updateStmt->close();
// }
header("Location: admin_index.php");
exit();
} else {
// 密码错误
logLoginAttempt($clientIP, false, $antiSpamConfig);
$stmt->close();
echo "<script>alert('用户名或密码错误!请重新登录!'); location.href='login.php';</script>";
exit();
}
} else {
// 用户不存在
logLoginAttempt($clientIP, false, $antiSpamConfig);
$stmt->close();
echo "<script>alert('用户名或密码错误!请重新登录!'); location.href='login.php';</script>";
exit();
}
$stmt->close();
}
// 退出登录逻辑
if (isset($_GET['tj']) && $_GET['tj'] == 'out') {
session_destroy();
header('location: login.php');
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="icon/favicon.ico" type="image/x-icon">
<title>图书后台管理系统登录功能</title>
<style>
.bg-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: -1;
}
.bg-item {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 1s ease-in-out;
}
.bg-item.active {
opacity: 1;
}
body * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-user-drag: none;
-moz-user-drag: none;
-ms-user-drag: none;
user-drag: none;
}
input, textarea {
-webkit-user-select: auto !important;
-moz-user-select: auto !important;
-ms-user-select: auto !important;
user-select: auto !important;
}
.copyright {
position: fixed;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
color: rgba(255,255,255,0.6);
font-size: 14px;
z-index: 100;
}
@keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
@keyframes slideInLeft { from { opacity: 0; transform: translateX(-50px); } to { opacity: 1; transform: translateX(0); } }
@keyframes slideInRight { from { opacity: 0; transform: translateX(50px); } to { opacity: 1; transform: translateX(0); } }
@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }
body {
margin: 0;
padding: 0;
font-family: 'Microsoft YaHei', sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
min-height: 100vh;
}
.big_box {
width: 960px;
height: 500px;
margin: auto;
background: rgba(255, 255, 255, 0.38);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
overflow: hidden;
border-radius: 20px 0 0 20px;
backdrop-filter: blur(5px);
display: flex;
position: relative;
z-index: 10;
}
.left_box {
width: 50%;
height: 100%;
overflow: hidden;
clip-path: ellipse(100% 100% at 0% 50%);
}
.left_box img {
width: 100%;
height: 100%;
object-fit: cover;
}
.right_box {
width: 50%;
text-align: center;
animation: slideInRight 0.8s ease-out;
display: flex;
flex-direction: column;
justify-content: center;
padding: 40px;
box-sizing: border-box;
background: transparent;
}
table {
margin: auto;
animation: fadeIn 1s ease-out;
width: 100%;
max-width: 320px;
}
h2 {
margin-top: 0;
color: #333;
animation: fadeIn 0.8s ease-out;
margin-bottom: 30px;
}
.iput {
width: 100%;
height: 40px;
border: 1px solid #ddd;
border-radius: 6px;
padding: 0 15px;
font-size: 14px;
background-color: rgba(255, 255, 255, 0.9);
}
.iput:focus {
border-color: #4a90e2;
box-shadow: 0 0 8px rgba(74, 144, 226, 0.2);
outline: none;
}
.iput1, .iut2 {
width: 120px;
height: 45px;
font-size: 15px;
margin: 0 10px;
cursor: pointer;
transition: all 0.3s;
}
.iput1 {
background-color: #4a90e2;
color: white;
border: none;
border-radius: 6px;
}
.iput1:hover {
background-color: #3a7bc8;
}
.iut2 {
background-color: #f5f5f5;
color: #333;
border: 1px solid #ddd;
border-radius: 6px;
}
.iut2:hover {
background-color: #e0e0e0;
}
.big_box.shake {
animation: shake 0.3s ease-in-out forwards;
}
tr {
height: 60px;
}
.verify-container {
position: relative;
}
.verify-code {
position: absolute;
right: 5px;
top: 50%;
transform: translateY(-50%);
height: 30px;
cursor: pointer;
border-radius: 4px;
}
.core-value {
position: absolute;
pointer-events: none;
font-size: 18px;
font-family: '微软雅黑';
color: #FF0000;
user-select: none;
z-index: 999;
transform: scale(0.1);
transition: transform 0.3s ease-out;
}
.core-value.active {
transform: scale(1);
}
</style>
</head>
<body oncontextmenu="return false;" ondragstart="return false;" onselectstart="return false;">
<div class="bg-container" id="bgContainer">
<img src="image/2.png" alt="背景1" class="bg-item">
<img src="image/4.png" alt="背景2" class="bg-item active">
<img src="image/5.png" alt="背景3" class="bg-item">
<img src="image/1.jpg" alt="背景4" class="bg-item">
</div>
<div class="big_box">
<div class="left_box"><img src="image/ysjf.jpg" draggable="false"></div>
<div class="right_box">
<h2>图书管理后台管理中心</h2>
<form method="post" action="" onsubmit="return check()">
<table>
<tr>
<td>
<input type="text" name="username" class="iput" placeholder="请输入用户名">
</td>
</tr>
<tr>
<td>
<input type="password" name="pwd" class="iput" placeholder="请输入密码">
</td>
</tr>
<tr>
<td>
<div class="verify-container">
<input type="text" name="code" class="iput" placeholder="请输入验证码">
<img src="verify.php" alt="验证码" class="verify-code" onclick="this.src='verify.php?'+Math.random()" draggable="false">
</div>
</td>
</tr>
<tr>
<td align="center">
<input type="submit" name="login" value="登录" class="iput1">
<input type="button" name="register" value="注册" class="iut2" onclick="window.location.href='register.php'">
</td>
</tr>
</table>
</form>
</div>
</div>
<div class="copyright">
@2025-05.22 由唯出品/gitee/github/4230603094
</div>
<script>
const bgImages = document.querySelectorAll('.bg-item');
let currentIndex = 0;
function switchBackground() {
bgImages[currentIndex].classList.remove('active');
currentIndex = (currentIndex + 1) % bgImages.length;
bgImages[currentIndex].classList.add('active');
}
document.addEventListener('DOMContentLoaded', function() {
setInterval(switchBackground, 5000);
// 完全禁止右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
});
// 禁止选择文本
document.addEventListener('selectstart', function(e) {
e.preventDefault();
});
// 禁止拖拽
document.addEventListener('dragstart', function(e) {
e.preventDefault();
});
// 输入框聚焦效果
const inputs = document.querySelectorAll('.iput');
inputs.forEach(input => {
input.addEventListener('focus', function() {
this.style.boxShadow = '0 0 8px rgba(74, 144, 226, 0.3)';
});
input.addEventListener('blur', function() {
this.style.boxShadow = '';
});
});
// 确保所有图片不可拖拽
document.querySelectorAll('img').forEach(img => {
img.draggable = false;
});
});
function check() {
const username = document.querySelector('input[name="username"]').value;
const password = document.querySelector('input[name="pwd"]').value;
const code = document.querySelector('input[name="code"]').value;
if (!username || !password || !code) {
alert('用户名、密码和验证码不可为空!');
return false;
}
return true;
}
const coreValues = [
'富强', '民主', '文明', '和谐',
'自由', '平等', '公正', '法治',
'爱国', '敬业', '诚信', '友善'
].flatMap(word => [word, word]);
document.addEventListener('click', (e) => {
if (e.button !== 0) return;
const x = e.clientX;
const y = e.clientY;
const randomIndex = Math.floor(Math.random() * coreValues.length);
const valueText = coreValues[randomIndex];
const span = document.createElement('span');
span.className = 'core-value';
span.textContent = valueText;
span.style.left = `${x}px`;
span.style.top = `${y}px`;
span.classList.add('active');
document.body.appendChild(span);
setTimeout(() => {
span.remove();
}, 1000);
});
</script>
</body>
</html>
Loading…
Cancel
Save