如何在PHP Slim框架中保障API端点安全?已遇未授权访问问题
解决Slim API未授权访问问题:仅允许认证用户访问
嘿,你的问题其实很典型——前端做了登录,但API本身没加身份校验拦截,导致任何人直接敲URL就能拉走敏感数据。下面给你几个适配Slim框架的实用方案,一步步搞定这个问题:
方案一:用JWT(JSON Web Token)做身份认证(前后端分离首选)
这是前后端分离项目最常用的方式,核心思路是:登录成功后后端给前端发一个加密令牌,前端每次请求API都带着这个令牌,后端校验令牌合法才放行。
安装JWT依赖
先在你的Slim项目里安装Firebase的JWT库,执行命令:composer require firebase/php-jwt后端生成JWT(登录接口改造)
当Angular前端发起登录请求,验证用户名密码正确后,生成JWT返回给前端:use Firebase\JWT\JWT; $app->post('/login', function ($request, $response) { $data = $request->getParsedBody(); // 这里写你的用户校验逻辑,比如查数据库验证账号密码 $user = checkUserCredentials($data['username'], $data['password']); if ($user) { $secretKey = getenv('JWT_SECRET'); // 密钥存在环境变量里,别硬编码! $payload = [ 'iss' => 'your-api-domain', // 签发者(你的API域名) 'aud' => 'your-angular-app', // 受众(你的前端应用标识) 'iat' => time(), // 签发时间 'exp' => time() + 3600, // 过期时间(1小时,可按需调整) 'user_id' => $user['id'] ]; $token = JWT::encode($payload, $secretKey, 'HS256'); return $response->withJson(['token' => $token]); } else { return $response->withStatus(401)->withJson(['error' => '用户名或密码错误']); } });创建Slim认证中间件
写一个中间件,用来校验每个请求的JWT是否合法:use Firebase\JWT\JWT; use Firebase\JWT\Key; class AuthMiddleware { public function __invoke($request, $handler) { // 从请求头获取Authorization字段 $authHeader = $request->getHeaderLine('Authorization'); // 没有令牌或者格式不对,直接返回401未授权 if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) { return $handler->handle($request)->withStatus(401)->withJson([ 'error' => '未授权访问,请先登录' ]); } // 提取令牌部分(去掉前面的"Bearer ") $token = substr($authHeader, 7); $secretKey = getenv('JWT_SECRET'); try { // 解码并校验令牌 $decoded = JWT::decode($token, new Key($secretKey, 'HS256')); // 把解码后的用户信息放进请求对象,后续路由可以直接调用 $request = $request->withAttribute('user', $decoded); } catch (\Exception $e) { // 令牌无效或过期,返回错误提示 return $handler->handle($request)->withStatus(401)->withJson([ 'error' => '无效或过期的登录令牌' ]); } // 校验通过,继续处理请求 return $handler->handle($request); } }给需要保护的路由添加中间件
你可以给单个路由加,也可以给整个路由组加,比如保护/slimapi/customers下的所有接口:// 给客户相关路由组添加认证中间件 $app->group('/slimapi/customers', function ($group) { $group->get('/view', function ($request, $response) { // 这里可以通过$request->getAttribute('user')拿到当前登录用户信息 $customers = // 查询客户数据的业务逻辑 return $response->withJson($customers); }); // 其他客户相关接口... })->add(new AuthMiddleware());前端Angular配置自动带令牌
用Angular的HttpInterceptor,让所有API请求自动在请求头带上Authorization: Bearer <token>,这样合法登录后的请求都会被API放行,而直接浏览器访问的话没有这个头,就会被拦截返回错误。
方案二:用Session+HttpOnly Cookie(同域项目适用)
如果你的Angular前端和Slim API是同域的,也可以用传统的Session认证:
登录接口启动Session
$app->post('/login', function ($request, $response) { session_start(); $data = $request->getParsedBody(); $user = checkUserCredentials($data['username'], $data['password']); if ($user) { $_SESSION['user_id'] = $user['id']; // 设置HttpOnly Cookie,防止XSS窃取Session setcookie('session_id', session_id(), time() + 3600, '/', '', true, true); return $response->withJson(['message' => '登录成功']); } else { return $response->withStatus(401)->withJson(['error' => '登录失败']); } });创建Session校验中间件
class SessionAuthMiddleware { public function __invoke($request, $handler) { session_start(); // 检查Session是否存在用户标识 if (!isset($_SESSION['user_id'])) { return $handler->handle($request)->withStatus(401)->withJson([ 'error' => '未授权访问,请先登录' ]); } return $handler->handle($request); } }给路由添加中间件
和JWT方案一样,把中间件加到需要保护的路由上即可。
额外安全提醒
- 别依赖检查
Referer头来限制访问,这个很容易被伪造,完全不安全 - 所有API请求必须用HTTPS,防止令牌或Session被窃听
- JWT要设置合理的过期时间,同时实现刷新令牌机制,避免用户频繁登录
- 敏感接口除了身份认证,还要加权限校验(比如普通用户只能看自己的客户数据,管理员才能看全部)
内容的提问来源于stack exchange,提问作者shehan96
相关产品推荐
相关产品推荐

