Linux下 ThinkPHP 权限控制实践
一 概念与总体架构
二 系统层面目录权限与安全防护
# 1) 调整属主/属组
chown -R demo:www-data /var/www/html/demo
# 2) 目录 750,文件 640
find /var/www/html/demo -type d -exec chmod 750 {} \;
find /var/www/html/demo -not -type d -exec chmod 640 {} \;
# 3) 对需要写入的目录(如 runtime、上传目录)放宽到 770
find /var/www/html/demo -name "runtime" -type d -exec chmod -R 770 {} \;
# 如有上传目录:find /var/www/html/demo -name "upload" -type d -exec chmod -R 770 {} \;
Order Allow,Deny
Deny from all
<FilesMatch "\.php$">
Order deny,allow
Deny from all
</FilesMatch>
<FilesMatch "^(.*)/config/.*\.php$">
Order deny,allow
Deny from all
</FilesMatch>
<FilesMatch "^(.*)/runtime/.*\.php$">
Order deny,allow
Deny from all
</FilesMatch>
三 应用层面 RBAC 与中间件实现
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`action` varchar(100) NOT NULL, -- 如:admin/user/list
PRIMARY KEY (`id`)
);
CREATE TABLE `user_roles` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`)
);
CREATE TABLE `role_permissions` (
`role_id` int(11) NOT NULL,
`permission_id` int(11) NOT NULL,
PRIMARY KEY (`role_id`,`permission_id`)
);
// app/middleware/Auth.php
namespace app\middleware;
use think\Request;
use think\facade\Session;
use app\model\User;
use app\model\Role;
use app\model\Permission;
class Auth
{
// 无需校验的白名单(如登录、验证码)
protected $whiteList = ['login', 'captcha'];
public function handle(Request $request, \Closure $next)
{
$controllerAction = strtolower($request->controller() . '/' . $request->action());
if (in_array($controllerAction, $this->whiteList, true)) {
return $next($request);
}
$userId = Session::get('user_id');
if (!$userId) {
return redirect('/login');
}
$user = User::with(['roles.permissions'])->find($userId);
if (!$user) {
Session::delete('user_id');
return redirect('/login');
}
// 将用户与权限注入到请求,便于控制器/视图使用
$request->user = $user;
$perms = [];
foreach ($user->roles as $role) {
foreach ($role->permissions as $perm) {
$perms[$perm->action] = true;
}
}
$request->userPerms = $perms;
// 校验当前请求是否在用户权限中
if (!isset($perms[$controllerAction])) {
return json(['code' => 403, 'msg' => '无权限'], 403);
}
return $next($request);
}
}
// 全局应用(示例)
// 或者在需要保护的路由组/控制器构造中绑定中间件
// app/controller/Index.php
public function login()
{
$username = $this->request->param('username');
$password = $this->request->param('password');
$user = User::where('username', $username)->find();
if ($user && password_verify($password, $user->password)) {
Session::set('user_id', $user->id);
return json(['status' => 'success', 'message' => '登录成功']);
}
return json(['status' => 'error', 'message' => '用户名或密码错误']);
}
四 常见问题与排查