本文目录导读:

在 PHP 中实现多用户类型登录,通常有以下几种设计方案,我将从最简单的方案到最灵活的架构逐一介绍,并给出完整的代码示例。
基于用户表字段区分(最简单)
这是最常见的做法,在 users 表中添加 role 字段(如:admin, teacher, student)。
数据库设计
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role ENUM('admin', 'teacher', 'student') NOT NULL DEFAULT 'student',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
登录处理代码
<?php
// login.php
session_start();
require_once 'db.php'; // 数据库连接
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$password = $_POST['password'];
if (empty($username) || empty($password)) {
$error = '用户名和密码不能为空';
} else {
// 预处理语句防止SQL注入
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user['password'])) {
// 登录成功,存储用户信息到session
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['role'] = $user['role'];
// 根据角色跳转到不同页面
switch ($user['role']) {
case 'admin':
header('Location: admin/dashboard.php');
break;
case 'teacher':
header('Location: teacher/dashboard.php');
break;
case 'student':
header('Location: student/dashboard.php');
break;
default:
header('Location: login.php?error=invalid_role');
}
exit;
} else {
$error = '用户名或密码错误';
}
}
}
?>
<!DOCTYPE html>
<html>
<head>多用户登录</title>
</head>
<body>
<form method="POST" action="">
<?php if ($error): ?>
<div style="color: red;"><?php echo $error; ?></div>
<?php endif; ?>
<input type="text" name="username" placeholder="用户名" required>
<input type="password" name="password" placeholder="密码" required>
<button type="submit">登录</button>
</form>
</body>
</html>
角色权限检查(中间件)
<?php
// check_auth.php - 角色权限检查
session_start();
function checkRole($allowed_roles = ['admin', 'teacher', 'student']) {
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
if (!in_array($_SESSION['role'], $allowed_roles)) {
header('Location: unauthorized.php');
exit;
}
}
// 使用示例:在 admin/dashboard.php 中
require_once 'check_auth.php';
checkRole(['admin']); // 只允许管理员
使用独立表(更专业)
每个用户类型有自己的数据表,通过 user_id 关联。
数据库设计
-- 用户主表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
user_type ENUM('admin', 'teacher', 'student') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 教师详细信息表
CREATE TABLE teachers (
id INT PRIMARY KEY,
user_id INT NOT NULL,
teacher_code VARCHAR(20) UNIQUE,
department VARCHAR(100),
hire_date DATE,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- 学生详细信息表
CREATE TABLE students (
id INT PRIMARY KEY,
user_id INT NOT NULL,
student_code VARCHAR(20) UNIQUE,
class_name VARCHAR(50),
enrollment_year YEAR,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- 管理员详细信息表
CREATE TABLE admins (
id INT PRIMARY KEY,
user_id INT NOT NULL,
admin_level INT DEFAULT 1,
last_login_ip VARCHAR(45),
FOREIGN KEY (user_id) REFERENCES users(id)
);
登录处理代码
<?php
// login.php - 更复杂的登录逻辑
session_start();
require_once 'db.php';
function getUserProfile($pdo, $user_id, $user_type) {
switch ($user_type) {
case 'teacher':
$stmt = $pdo->prepare("SELECT * FROM teachers WHERE user_id = ?");
break;
case 'student':
$stmt = $pdo->prepare("SELECT * FROM students WHERE user_id = ?");
break;
case 'admin':
$stmt = $pdo->prepare("SELECT * FROM admins WHERE user_id = ?");
break;
default:
return null;
}
$stmt->execute([$user_id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$password = $_POST['password'];
$user_type = $_POST['user_type']; // 前端选择用户类型
// 查找用户
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND user_type = ?");
$stmt->execute([$username, $user_type]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user['password'])) {
// 获取用户详细信息
$profile = getUserProfile($pdo, $user['id'], $user_type);
// 存储完整会话
$_SESSION['auth'] = [
'user_id' => $user['id'],
'username' => $user['username'],
'user_type' => $user_type,
'profile' => $profile,
'login_time' => time()
];
// 记录登录日志
$stmt = $pdo->prepare("INSERT INTO login_logs (user_id, login_time, ip_address) VALUES (?, NOW(), ?)");
$stmt->execute([$user['id'], $_SERVER['REMOTE_ADDR']]);
// 跳转
$redirect_map = [
'admin' => '/admin/dashboard.php',
'teacher' => '/teacher/dashboard.php',
'student' => '/student/dashboard.php'
];
header('Location: ' . $redirect_map[$user_type]);
exit;
} else {
$error = '用户名/密码/用户类型不匹配';
}
}
?>
使用 RBAC(角色权限控制) - 最灵活
这是企业级应用最常用的方案,适合权限复杂的系统。
数据库设计
-- 用户表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE roles (
id INT AUTO_INCREMENT PRIMARY KEY,
role_name VARCHAR(50) UNIQUE NOT NULL,
role_description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 用户-角色关联表(一个用户可以有多个角色)
CREATE TABLE user_roles (
user_id INT NOT NULL,
role_id INT NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
-- 权限表
CREATE TABLE permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
permission_name VARCHAR(50) UNIQUE NOT NULL,
module VARCHAR(50) NOT NULL,
action VARCHAR(50) NOT NULL
);
-- 角色-权限关联表
CREATE TABLE role_permissions (
role_id INT NOT NULL,
permission_id INT NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
);
RBAC 核心类
<?php
// RBAC.php - 权限控制核心类
class Rbac {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
// 获取用户的所有角色
public function getUserRoles($user_id) {
$stmt = $this->pdo->prepare("
SELECT r.role_name FROM roles r
INNER JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id = ?
");
$stmt->execute([$user_id]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
// 检查用户是否有特定权限
public function hasPermission($user_id, $module, $action) {
$stmt = $this->pdo->prepare("
SELECT COUNT(*) FROM user_roles ur
INNER JOIN role_permissions rp ON ur.role_id = rp.role_id
INNER JOIN permissions p ON rp.permission_id = p.id
WHERE ur.user_id = ?
AND p.module = ?
AND p.action = ?
");
$stmt->execute([$user_id, $module, $action]);
return $stmt->fetchColumn() > 0;
}
// 检查用户是否有特定角色
public function hasRole($user_id, $role_name) {
$roles = $this->getUserRoles($user_id);
return in_array($role_name, $roles);
}
// 获取用户的最大权限级别
public function getMaxRoleLevel($user_id) {
$stmt = $this->pdo->prepare("
SELECT MIN(id) as level FROM roles
WHERE id IN (
SELECT role_id FROM user_roles WHERE user_id = ?
)
");
$stmt->execute([$user_id]);
return $stmt->fetchColumn() ?? 999;
}
}
权限检查使用方法
<?php
// 在任何需要权限的页面中使用
session_start();
require_once 'db.php';
require_once 'RBAC.php';
$rbac = new Rbac($pdo);
// 方式1:检查角色
if (!$rbac->hasRole($_SESSION['user_id'], 'admin')) {
header('Location: /403.php');
exit;
}
// 方式2:检查具体操作权限
if (!$rbac->hasPermission($_SESSION['user_id'], 'user', 'delete')) {
header('Location: /403.php');
exit;
}
// 方式3:在函数中使用
function requirePermission($pdo, $module, $action) {
$rbac = new Rbac($pdo);
if (!isset($_SESSION['user_id']) || !$rbac->hasPermission($_SESSION['user_id'], $module, $action)) {
throw new Exception("权限不足");
}
}
JWT Token 认证(API 场景)
如果你是做前后端分离的 API 服务,可以使用 JWT 认证。
<?php
// jwt_auth.php - JWT 认证类
require_once 'vendor/autoload.php'; // 使用firebase/php-jwt库
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JwtAuth {
private $secret_key = 'your-secret-key';
private $algorithm = 'HS256';
// 生成Token
public function generateToken($user_id, $user_type, $expire_hours = 24) {
$payload = [
'user_id' => $user_id,
'user_type' => $user_type,
'iat' => time(),
'exp' => time() + ($expire_hours * 3600)
];
return JWT::encode($payload, $this->secret_key, $this->algorithm);
}
// 验证Token
public function validateToken($token) {
try {
$decoded = JWT::decode($token, new Key($this->secret_key, $this->algorithm));
return $decoded; // 返回解析后的payload
} catch (Exception $e) {
return null; // Token无效
}
}
// 获取当前用户信息
public function getCurrentUser($token) {
$decoded = $this->validateToken($token);
if (!$decoded) {
return null;
}
return [
'user_id' => $decoded->user_id,
'user_type' => $decoded->user_type
];
}
}
// 登录API示例
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $path === '/api/login') {
$data = json_decode(file_get_contents('php://input'), true);
$username = $data['username'];
$password = $data['password'];
$user_type = $data['user_type'];
// ... 验证用户密码 ...
// 生成token
$jwtAuth = new JwtAuth();
$token = $jwtAuth->generateToken($user['id'], $user_type);
header('Content-Type: application/json');
echo json_encode(['token' => $token]);
}
最佳实践建议
- 密码安全:永远使用
password_hash()和password_verify() - 防SQL注入:使用 PDO 预处理语句
- CSRF防护:使用 CSRF Token
- 会话安全:session 设置
httponly和samesite - 角色权限分离:根据需求选择最合适的方案
- 登录日志:记录登录时间、IP、设备等
前端用户类型选择界面
<!-- login_form.html -->
<form action="login.php" method="POST">
<select name="user_type" required>
<option value="">选择用户类型</option>
<option value="admin">管理员</option>
<option value="teacher">教师</option>
<option value="student">学生</option>
</select>
<input type="text" name="username" placeholder="用户名" required>
<input type="password" name="password" placeholder="密码" required>
<!-- CSRF Token -->
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<button type="submit">登录</button>
</form>
选择哪种方案主要取决于你的项目需求:
- 小项目:方案一(角色字段)就够了
- 中大型项目:方案二(独立表)更结构化
- 复杂权限系统:方案三(RBAC)最灵活
- API服务:方案四(JWT)是现代首选
建议从方案一开始,随着需求增长再逐步升级。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播