ThinkPHP 作为国内使用最广泛的 PHP 框架之一,在中高级 PHP 岗位的面试中出现频率极高。面试官往往不会只问你“怎么用”,而是围绕安全、鉴权、权限三个维度层层深入,考察你对框架底层机制的理解和实际项目中的落地能力。本文整理了这三类高频面试题,并给出参考答案与延伸思路,帮助你在面试中从容应对。
一、安全类高频面试题
1. ThinkPHP 如何防止 SQL 注入?
这是安全类必问题。核心回答要点:
- 使用查询构造器或模型:TP 的
Db::name()、Db::table()以及模型查询底层使用 PDO 预处理(prepare + bind),参数与 SQL 语句分离,从根本上避免注入。 - 使用参数绑定:
where('id', $id)会自动绑定;手写 SQL 时用Db::query('select * from user where id = ?', [$id])。 - 避免字符串拼接:
where("id = $id")或whereRaw直接拼接变量是典型错误写法。 - 字段与表名白名单:
order('id desc')这类无法参数绑定的位置,必须用白名单校验,否则仍可能被注入。
延伸追问:TP6 的 whereRaw 和 whereExp 有什么区别?答:whereRaw 用于原生条件但支持绑定,whereExp 是表达式查询,二者都需谨慎处理变量。
2. XSS 攻击在 ThinkPHP 中如何防御?
- 输出转义:模板中使用
{$name|htmlspecialchars}或 TP 默认的{$name}(TP6 模板默认对变量做转义处理,但需确认配置)。 - 富文本场景:不能简单转义,需使用 HTMLPurifier 等库做白名单过滤。
- CSP 响应头:在中间件中设置
Content-Security-Policy。 - HttpOnly Cookie:防止 JS 读取会话 Cookie。
3. CSRF 如何防护?
TP 内置了 token 机制:
- 模板中加
{:token()}生成隐藏域; - 控制器用
$this->request->checkToken()或验证器token规则校验; - 也可在中间件中统一校验
__token__字段。
面试加分点:说明 CSRF 的本质是“浏览器自动携带凭证”,因此 SameSite Cookie 也是有效防线。
4. 文件上传安全要注意什么?
- 校验 MIME 类型与扩展名双重白名单;
- 重命名文件,避免用户控制路径(防目录穿越
../); - 上传目录禁止 PHP 执行权限(Nginx 配置
location ~* \.php$ { deny all; }); - 使用 TP 的
$file->validate()和move()方法,而非move_uploaded_file裸操作。
二、鉴权类高频面试题
1. Session 与 Token 鉴权的区别?TP 中如何实现?
| 维度 | Session | Token(JWT) |
|---|---|---|
| 存储 | 服务端 | 客户端 |
| 扩展性 | 需共享存储 | 无状态,易横向扩展 |
| 失效控制 | 服务端可即时销毁 | 需黑名单或短过期 |
TP6 中 JWT 常用 firebase/php-jwt 或 tymon/jwt-auth 的移植方案。典型流程:登录签发 token → 中间件解析 Authorization 头 → 校验签名与过期 → 将用户信息注入 Request。
2. 如何实现“单点登录”或“同一账号只能一处登录”?
思路:登录时生成唯一 jti 或随机 session_key 存入 Redis,key 为用户 ID。每次请求校验 token 中的 jti 与 Redis 中是否一致,不一致则踢下线。新登录覆盖旧值即实现互踢。
3. 中间件鉴权的执行顺序问题
TP6 中间件分全局、应用、路由、控制器四级,执行顺序为:全局 → 应用 → 路由 → 控制器。鉴权中间件通常注册在路由或应用级。面试常问:如果中间件里 return 了响应,后续中间件还会执行吗? 答:不会,会直接短路返回,这正是鉴权拦截的原理。
三、权限类高频面试题
1. RBAC 模型在 ThinkPHP 中如何设计?
标准五表设计:
user用户表role角色表user_role用户角色关联permission权限节点表(如user/list、user/edit)role_permission角色权限关联
校验逻辑:用户 → 角色 → 权限节点集合,判断当前请求的“模块/控制器/方法”是否在集合内。TP 中可封装成 Auth 服务或中间件,结合 Request::controller()、Request::action() 获取节点。
2. 权限节点如何自动生成与维护?
- 基于注解或路由扫描自动收集节点,写入
permission表; - 或使用 TP 的
Route::rule()注册时统一记录; - 超级管理员用
is_admin字段或*通配跳过校验。
3. 数据权限与功能权限的区别?
- 功能权限:能不能访问某个接口(RBAC 解决)。
- 数据权限:能看哪些数据(如只能看本部门订单)。实现方式是在查询构造器中动态追加
where条件,例如根据当前用户dept_id过滤。面试中能区分这两层,是明显的加分项。
4. 权限缓存在哪里?如何失效?
权限判断频繁,通常缓存到 Redis,key 为 user:perm:{uid}。角色或权限变更时,删除相关用户的缓存 key。注意缓存雪崩与穿透,可加随机过期时间。
四、面试应答策略
- 先讲原理再讲实现:面试官更看重你是否理解“为什么”,而不只是“怎么写”。
- 结合项目举例:把 RBAC、JWT、中间件串成一个真实登录鉴权链路讲出来,比零散回答更有说服力。
- 主动提边界与风险:比如 token 无法即时失效、缓存一致性、越权漏洞,展现安全意识。
- 熟悉源码级细节:如 TP6 中间件管道
Pipeline的实现、Request生命周期,能显著提升技术深度评分。
掌握以上三类问题的核心逻辑,你不仅能答对题,更能让面试官看到你具备独立设计和排查安全问题的能力,这正是中高级 PHP 岗位真正看重的东西。
未经允许不得转载:任鹏个人博客 » ThinkPHP 面试精讲:安全、鉴权与权限高频面试题

