本文目录导读:

在PHP API开发中,权限控制是一个核心的安全问题,常见的控制方式包括以下几种,从简单到复杂:
基于角色的访问控制 (RBAC)
这是最基础的权限控制方式。
数据库设计
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE,
password VARCHAR(255),
role_id INT
);
-- 角色表
CREATE TABLE roles (
id INT PRIMARY KEY,
role_name VARCHAR(50) -- admin, user, guest
);
-- 权限表
CREATE TABLE permissions (
id INT PRIMARY KEY,
permission_name VARCHAR(100) -- user.create, user.delete, article.edit
);
PHP实现示例
class ApiAuth {
private $rolePermissions = [
'admin' => ['user.create', 'user.delete', 'article.edit', 'article.delete'],
'editor' => ['article.edit', 'article.create'],
'user' => ['article.read']
];
public function checkPermission($userId, $requiredPermission) {
$user = $this->getUser($userId);
$role = $user['role'];
if (!isset($this->rolePermissions[$role])) {
return false;
}
return in_array($requiredPermission, $this->rolePermissions[$role]);
}
}
// 在API路由中使用
$auth = new ApiAuth();
if (!$auth->checkPermission($_GET['user_id'], 'article.edit')) {
http_response_code(403);
echo json_encode(['error' => '无权限']);
exit;
}
JWT (JSON Web Token) 鉴权
这是目前最流行的API权限控制方式。
实现步骤
// 1. 生成JWT Token
use Firebase\JWT\JWT;
class JwtAuth {
private $secretKey = 'your-secret-key';
private $algorithm = 'HS256';
public function generateToken($userData) {
$payload = [
'iss' => 'your-domain.com', // 签发者
'iat' => time(), // 签发时间
'exp' => time() + 7200, // 过期时间2小时
'user_id' => $userData['id'],
'role' => $userData['role'],
'permissions' => $userData['permissions']
];
return JWT::encode($payload, $this->secretKey, $this->algorithm);
}
public function validateToken($token) {
try {
$decoded = JWT::decode($token, $this->secretKey, [$this->algorithm]);
return (array) $decoded;
} catch (Exception $e) {
return false;
}
}
}
// 2. 中间件检查权限
function apiMiddleware($requiredPermission) {
$headers = getallheaders();
$token = str_replace('Bearer ', '', $headers['Authorization'] ?? '');
$jwt = new JwtAuth();
$userData = $jwt->validateToken($token);
if (!$userData) {
http_response_code(401);
echo json_encode(['error' => '未授权']);
exit;
}
// 检查权限
if (!in_array($requiredPermission, $userData['permissions'])) {
http_response_code(403);
echo json_encode(['error' => '权限不足']);
exit;
}
return $userData;
}
// 3. 在路由中使用
Route::get('/api/articles', function() {
$userData = apiMiddleware('article.read');
// 继续处理请求...
});
Route::post('/api/articles', function() {
$userData = apiMiddleware('article.create');
// 继续处理请求...
});
OAuth 2.0 授权框架
适用于第三方应用接入的场景。
简化的OAuth实现
class OAuthServer {
private $clients = [
'app1' => ['secret' => 'sec123', 'redirect_uri' => 'http://app1.com/callback']
];
// 授权码模式
public function authorize($clientId, $redirectUri, $scope) {
// 验证客户端
if (!isset($this->clients[$clientId])) {
throw new Exception('无效客户端');
}
// 生成授权码
$authCode = bin2hex(random_bytes(16));
// 保存授权码到数据库
$this->saveAuthCode($authCode, $clientId, $scope);
// 重定向回客户端
header("Location: {$redirectUri}?code={$authCode}");
}
// 换取Access Token
public function getAccessToken($code, $clientId, $clientSecret) {
// 验证客户端凭证
if ($this->clients[$clientId]['secret'] !== $clientSecret) {
throw new Exception('无效凭证');
}
// 验证授权码
$authData = $this->validateAuthCode($code);
// 生成Access Token
$accessToken = bin2hex(random_bytes(32));
$refreshToken = bin2hex(random_bytes(32));
return [
'access_token' => $accessToken,
'refresh_token' => $refreshToken,
'expires_in' => 3600,
'scope' => $authData['scope']
];
}
}
细粒度权限控制 (ACL)
适用于复杂权限需求。
PHP实现
class AclController {
private $acl = [];
public function __construct() {
// 定义用户资源的权限
$this->acl = [
'user_id_1' => [
'resource_1' => ['read', 'write'],
'resource_2' => ['read']
],
'user_id_2' => [
'resource_1' => ['read']
]
];
}
public function checkAccess($userId, $resourceId, $action) {
if (!isset($this->acl[$userId])) {
return false;
}
if (!isset($this->acl[$userId][$resourceId])) {
return false;
}
return in_array($action, $this->acl[$userId][$resourceId]);
}
public function addPermission($userId, $resourceId, $actions) {
if (!isset($this->acl[$userId])) {
$this->acl[$userId] = [];
}
$this->acl[$userId][$resourceId] = $actions;
}
}
中间件实现模式
Laravel风格中间件
class PermissionMiddleware {
private $permissionMap = [
'GET' => 'read',
'POST' => 'create',
'PUT' => 'update',
'DELETE' => 'delete'
];
public function handle($request, $next) {
$method = $request->getMethod();
$resource = $request->getPathInfo();
$action = $this->permissionMap[$method];
// 从Token获取用户信息
$user = $this->getUserFromToken($request);
if (!$this->hasPermission($user, $resource, $action)) {
return response()->json([
'error' => '权限不足',
'code' => 403
], 403);
}
return $next($request);
}
}
最佳实践建议
使用开源库
- PHP-JWT:
firebase/php-jwt - OAuth2:
thephpleague/oauth2-server - ACL: 自行实现或使用
zendframework/zend-permissions-acl
安全注意事项
// 1. 使用HTTPS
// 2. Token存储在header中,不在URL传递
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
// 3. Token定期轮换
if ($token['exp'] < time()) {
// 刷新token
}
// 4. 记录操作日志
$logger->info("User {id} accessed {resource}", [
'id' => $userId,
'resource' => $resource
]);
性能优化
// 1. 缓存权限数据
$cacheKey = "permissions:{$userId}";
$permissions = $cache->get($cacheKey);
if (!$permissions) {
$permissions = $db->query("SELECT * FROM user_permissions WHERE user_id = ?", [$userId]);
$cache->set($cacheKey, $permissions, 3600);
}
// 2. 使用Redis存储Token
$redis->set("token:{$accessToken}", json_encode($userData), 3600);
选择哪种方式取决于你的项目规模和安全需求,对小项目使用JWT+RBAC就足够了,大型系统可能需要OAuth2.0或更复杂的权限模型。