前端权限控制能保证安全吗?路由守卫和按钮权限应该怎么做?
简化版
前端权限控制只能改善体验和减少误操作,不能作为真正安全边界。路由守卫、菜单权限、按钮权限都可能被用户绕过;关键接口必须由服务端基于用户身份和权限重新校验。
详细版
前端常做三层权限:菜单是否展示、路由是否可进入、按钮或操作是否可点击。它们应来自服务端下发的权限数据,并在前端做缓存和渲染控制。
router.beforeEach((to, from, next) => {
if (!auth.isLogin()) return next('/login')
if (to.meta.permission && !auth.has(to.meta.permission)) return next('/403')
next()
})
但用户可以直接改前端状态、调用接口、构造请求或绕过按钮。因此所有写操作、敏感查询、导出、审批、管理接口都必须在后端鉴权。面试中要把前端权限定位为“体验层控制”,后端权限定位为“安全层控制”。
完整版教学
一、为什么前端权限不是安全边界
前端代码运行在用户浏览器里,用户能看到代码、修改内存、调用接口、伪造请求。隐藏按钮只能阻止普通用户误点,不能阻止攻击者在控制台里调用接口。
// 控制台里可以直接尝试请求
fetch('/api/admin/users', { credentials: 'include' })
记忆钩子:前端管“看不看得到”,后端管“能不能真的做”。
二、前端权限控制的三层
| 层级 | 作用 | 安全边界 |
|---|---|---|
| 菜单权限 | 不展示无权限入口 | 不是 |
| 路由守卫 | 进入页面前拦截 | 不是 |
| 按钮权限 | 隐藏或禁用操作按钮 | 不是 |
| 接口鉴权 | 服务端校验身份和权限 | 是 |
这几层都要做,但目的不同。前端层让产品体验清晰,后端层保证攻击者不能越权。只做后端不做前端,用户体验差;只做前端不做后端,系统不安全。
三、路由守卫怎么设计
const routes = [
{ path: '/users', component: Users, meta: { permission: 'user:list' } },
{ path: '/admin', component: Admin, meta: { permission: 'admin:entry' } },
]
router.beforeEach(async (to, from, next) => {
if (!auth.token) return next('/login')
if (!auth.permissionsLoaded) await auth.loadPermissions()
if (to.meta.permission && !auth.has(to.meta.permission)) return next('/403')
next()
})
守卫要处理刷新后权限未加载的情况。很多 bug 出在首屏刷新:内存里的权限丢了,路由先判断失败,导致用户被错误踢到 403。通常要先恢复登录态、拉取用户信息和权限,再做路由判断。
四、按钮权限和操作权限
function can(permission) {
return userPermissions.has(permission)
}
// 模板中只展示有权限的按钮
// v-if="can('user:delete')"
按钮权限适合控制删除、导出、审批、配置等敏感操作的入口。但按钮隐藏不等于接口安全,攻击者可以直接调用 /api/user/delete。后端必须根据当前用户、资源归属、角色和数据范围再次判断。
一个常见数字例子:页面隐藏了 1 个“删除用户”按钮,但接口没有鉴权;攻击者只要知道 1 个接口路径,就可能删除 1000 条数据。前端少显示 1 个按钮,挡不住直接请求。
五、RBAC、ABAC 与数据权限
| 模型 | 判断依据 | 例子 |
|---|---|---|
| RBAC | 用户拥有哪些角色 | 管理员、运营、访客 |
| Permission | 用户拥有哪些动作权限 | user:create、order:export |
| ABAC | 属性和上下文 | 部门、地区、时间、资源归属 |
| 数据权限 | 能看哪些数据范围 | 只能看本部门订单 |
前端常拿到的是菜单树和动作权限码,但真正复杂的是数据权限。用户能进入订单页,不代表能看所有订单;服务端查询时必须加租户、组织、资源归属等条件。
六、接口鉴权要覆盖什么
请求 -> 身份认证 -> 权限校验 -> 数据范围校验 -> 审计日志 -> 执行业务
后端不能只判断“是否登录”。还要判断用户是否有该动作权限、是否能操作该资源、是否跨租户、是否超过数据范围。前端传来的 role=admin、userId=123、tenantId=1 都不能直接信任。
对于导出、批量删除、审批通过这类高风险操作,后端还应记录审计日志,必要时增加二次确认或风控。
七、常见误区与追问
- 误区:隐藏按钮就完成权限控制。 用户可以直接构造请求,按钮权限只是体验控制。
- 误区:路由守卫可以保护接口。 守卫只在前端运行,接口必须服务端鉴权。
- 误区:JWT 里有角色就完全可信。 后端要验证签名、有效期、撤销状态和最新权限。
- 追问:刷新后权限丢失怎么办? 先恢复身份并拉取权限,再执行路由判断。
- 追问:菜单权限和数据权限有什么区别? 菜单控制入口,数据权限控制能看或操作哪些资源。
- 追问:前端传
isAdmin=true能信吗? 不能,权限必须以后端可信身份和服务端数据为准。
八、加强记忆
前端权限控制要用“两层边界”记:前端边界是体验边界,负责菜单、路由、按钮;后端边界是安全边界,负责认证、动作权限、资源归属和数据范围。面试回答不能把前端守卫说成安全方案,必须明确所有敏感接口都要在服务端重新校验。