在前后端分离的模式下,所有的交互场景都变成了数据交互,因此传统业务系统中的权限控制方案在前端已经不再适用(比如使用后台模板标签进行权限控制),需要另外设计权限控制方案。
权限控制的概念
要理解权限控制,需要明白两个概念:资源和权限。
资源:对于一个系统来说,系统内部的所有信息都可以理解为是这个系统的资源。页面是资源、数据是资源、按钮是资源、图片也是资源。
权限:权限就是访问某个资源所需要的标识。无论系统的权限如何设计,在用户登陆的时候都需要计算当前登陆用户所拥有的权限标识集合,这样才能确定这个用户所能访问的系统资源。
由上面可以得出,权限控制是控制登陆用户对于系统资源的访问。
前后端在权限控制中各自的职责
要弄清前后端在权限控制中各自的职责,需要明白前后端在系统中各自的职责。
服务端:提供数据接口。
前端:路由控制、页面渲染。
由于前端负责与用户交互,这就意味着,用户所能操作的资源入口就都是由前端进行控制,那么前端的权限控制就包括了前端路由的权限控制和页面内组件的权限控制。
前端路由的权限控制:过滤非法请求,用户只能访问权限范围之内的页面资源。
页面内组件的权限控制:根据用户的权限控制页面组件的渲染,包括各种按钮、表格和分割线等。
随着前端组件化的快速发展,用户所看到的一切都可以理解为组件。页面是一个大组件,其内部由各种小组件拼凑而来,那么前端权限的控制最终就落地到了对组件的权限控制。
<组件 permission='xxx' />
这样,前端就可以渲染出用户权限范围内的各种系统资源。但是却不能保证数据接口的安全性,因为某些比较喜欢折腾的用户完全可以越过前端的页面访问系统的数据接口。服务端的权限控制最终还是要落地到对接口的权限验证。
简单实现
理论上来说,系统的一切资源都是可以进行权限控制的,实际上也可以做得到,只是实际场景中并不需要细化到页面上一条分割线这种程度,最细的粒度一般只是到按钮级别。
前端
前端路由权限控制,可以通过在用户登陆的时候存储在前端的用户所拥有的权限标识集合,在路由变化时进行权限判断。具体是,权限验证通过则渲染对应页面,否则渲染403组件。
let hasPermission = permission.check(current.permissionName); <div className={styles.content}> {hasPermission ? children : <Exception type={403}/>} </div>
服务端
服务端的权限验证很好理解,一个最简单的实现是使用拦截器验证当前请求的权限。
public class SsoAuthorizeInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 校验权限 } }
总结
所有业务组件的设计理念均是要结合服务端接口进行组件的封装,兼顾灵活性的同时可以保证更优的业务开发速度。
"不可能实现的诺言最动人。"