php权限控制需守住四大防线:密码用password_hash()哈希存储;登录态优先用$_session并防会话劫持;权限判断须抽离为统一检查点;登出需清session、cookie及再生id。

PHP框架里加权限控制,不是非得抄 Laravel 的 Auth 或用现成包——但硬从零手写一个“能用、不翻车”的 Auth 模块,对新手来说容易在中间环节踩坑,比如会话劫持没防、密码没哈希、角色判断逻辑错位、中间件没正确拦截。真要自己实现,重点不在“写多少代码”,而在守住几个关键防线。
怎么存用户凭证才不算埋雷
别直接存明文密码,也别用 md5() 或 sha1()——这些函数不可加盐、不可调慢,早被跑库秒破。PHP 7.2+ 唯一推荐的是 password_hash() 和 password_verify()。
-
password_hash($password, PASSWORD_ARGON2ID)(优先)或PASSWORD_DEFAULT,后者目前指向 bcrypt,兼容性更好 - 数据库字段至少留 255 字符,bcrypt 哈希长度约 60,Argon2 可达 190+
- 千万别自己拼 salt、别用
uniqid()生成 salt——password_hash()已全自动处理
登录态怎么管,session 还是 token
新手建议先用 PHP 原生 $_SESSION,简单可控;JWT 看似时髦,但密钥管理、刷新逻辑、黑名单注销全是额外负担,一上来就上反而更易出错。
- 登录成功后必须调
session_start(),再写$_SESSION['user_id'] = $id,别漏session_regenerate_id(true)防固定会话攻击 - session 存储路径若用默认
/tmp,多项目可能冲突;可统一设为session_save_path('/path/to/myapp-sessions') - 别在 session 里存敏感字段如密码、权限列表——只存
user_id,每次请求查 DB 或缓存拿角色/权限
权限判断写在哪?别堆在控制器里
把 if ($user->role !== 'admin') die('no access') 散落在各个控制器动作里,后期根本没法维护。必须抽成可复用的检查点。
立即学习“PHP免费学习笔记(深入)”;
- 最轻量做法:写个
requireRole($role)函数,内部查$_SESSION['user_id']→ 查库 → 判断 → 不通过就header('Location: /login')+exit - 进阶一点:模仿中间件,在路由分发前统一调用,比如
checkPermission('post:delete'),背后查的是「用户拥有的权限字符串集合」而非仅角色名 - 注意:权限判断必须发生在输出任何 HTML 之前,否则
header()会报headers already sent
登出和会话销毁容易漏哪几步
很多人只写 $_SESSION = [] 或 session_destroy(),但这就够了吗?不够。
- 必须同时删客户端 cookie:
setcookie(session_name(), '', time() - 3600, '/', '', false, true) - 如果用了自定义 session 路径,确保
session_save_path()在登出前后一致,否则session_destroy()可能删错地方 - 登出后重定向到登录页前,加
session_regenerate_id(true)再清空,避免会话 fixation
真正难的不是写完登录注册,而是想清楚:密码改了旧 token 是否自动失效?用户被禁用后当前 session 还能活多久?API 和网页共用一套鉴权时,CSRF 怎么防?这些问题不提前想,模块上线后就是线上事故。










