基于角色的权限控制(RBAC)是管理用户对某种资源或操做的权限的通用方法。权限能够明确指定能够访问的资源和操做。基本原理以下:权限将被分配给某个角色,并将该角色分配给某个用户或者是用户组,而不是直接分配给某个用户。面试
将权限与单个用户关联起来是一件很复杂的事情,随着更多的用户使用系统,维护用户的权限变得更加困难,且容易出错。权限的错误分配会阻止用户访问所需的系统,甚至是容许非受权用户访问限制区域或是执行危险操做。spring
在这篇文章中,我会介绍如何对应用开启权限控制。权限控制的模型有许多种,好比RBAC(基于角色的权限控制),DAC(自由访问控制)等。虽然文档中解释的原则能够应用于各类模型,但我选择RBAC做为参考,由于它被普遍接受而且很是直观。数组
查看用户的活动一般只会产生用户执行的有限数量的操做(如读取数据,提交表单)。深刻观察这些用户的行为会发现,这些行为一般一块儿执行,即执行A操做的用户每每也会执行B操做。好比,读取并更新报告,或者是添加和删除用户。这些均可以与角色绑定,好比编辑或是帐户管理员。注意这里的角色并不必定和职称或是组织结构绑定,而是以有意义的方式反映相关的用户操做。当恰当划分好角色并分配给用户时,就能够将权限分配给每一个角色,而非用户。管理少许角色的权限是一件相对简单的事情。微信
以下,是没有角色做为中介的权限与用户图:架构
而以下,则是彻底相同的用户和权限集,由角色组织:框架
显而易见,角色使得权限管理更容易了dom
将用户与群组绑定是一种更好的实践。工具
在观察用户关于上述角色的行为模式时,咱们常常发现用户之间有不少共同之处,好比某一组用户经常行为类似--在共同的资源上执行相同的操做。这容许咱们将用户组织到组中,而后将角色分配给少数组,而不是许多用户。好比,会发现一组用户都须要系统管理员权限,所以咱们新建一个名叫帐户管理员的群组,将用户添加到该组并将该角色分配给该组,而不是每一个用户。spa
在许多系统中,开发人员经过直接在实现方法上指定权限来限制对特定操做的访问。没错,就在代码上!一般,角色的验证经过注解添加到须要检查的方法上,好比这里提供了一个spring-security的一个范例:设计
@PreAuthorize("hasRole('Editor')") public void update_order(Order order);
在不一样语言和框架中,这种作法很是常见。虽然很容易实现,但遗憾的是,它在所需角色和动做的实现之间产生了不但愿的耦合。想象一下有几十个方法都须要添加这样的注解。跟踪每个角色的有效操做将会变得很艰难,几乎确定会致使依赖于不许确或过期的文档,或者更糟糕的是 - 分散在您的应用程序中的未知,非托管权限。
从客户的角度来看,这种耦合使得没法修改开发人员事先定义的角色集或者他们的权限,由于更改它意味着每次都必须编译和打包代码!这种用户体验也许不是咱们的目标。
更好的方式是,首先从要由外部受权机制处理的代码中提取可能的操做列表,而后,咱们可使代码不知道角色或任何其余受权细节,简单地询问当前用户(不管它是否被检索)是否具备执行特定方法所需的权限(不管在何处定义)。
这容许咱们使用更加通用的注解,以下所示:
@Secured public void update_order(Order order);
角色和权限的映射(即执行特定操做的权限)如今能够在配置文件中完成,能够由客户轻松定制!
好比,假设有这样的一个roles_config.yml文件:
order_manager: - 'create_order' - 'view_order' - 'delete_order' - 'update_order' order_inspector: - 'viewer_order'
由@secured注解的方法回去查询配置文件肯定当前用户是否具备执行该操做的权限。这意味着当前用户必须具备order_manager的角色,而这一点也是很容易配置的。可是,受权机制必须知道如何将每一个权限与代码中的特定方法相匹配,而且有人必须记录全部可用的方法(即create_order,view_order等)。
既然方法实现代码不包含受权细节,整个受权逻辑能够移动到单独的独立模块。经过使用通用标题(例如注解@secure
),咱们容许修改整个受权机制而不影响应用程序的代码。例如,能够将@secure
实现为基于角色的检查,但也可使用访问控制列表(ACL)。好比,检查当前用户是否列在订单的ACL列表中。另外一种解决方案能够是经过询问第三方是否容许用户执行该动做来使用oauth。
REST接口确定更好,或者至少是最容易匹配这个模型的。设计良好的Rest服务经过标准的基于HTTP的API暴露资源和方法,资源经过URI定义,方法经过HTTP动词(如GET,PUT)等定义。
好比,POST http://www.domain.com/bookings
会建立一本新书,而GET http://www.domain.com/orders/12345
会返回订单#12345的详情。这意味着能够垂手可得的得到资源的名称和对资源的操做。
除了标准的建模操做以外,REST服务一般是请求流中评估身份验证和受权的好地方,由于这一般是系统的主要入口点。为了使访问控制机制有意义,建议阻止全部其余到系统的路由,例如直接访问数据存储或代码中的任何远程调用机制。该架构的另外一个重要优势是响应过滤,以防某些不该当返回给用户的数据写在响应中。
REST服务处理传入请求,这意味着请求中找到的信息可用于制定访问控制决策。一些有用的细节是:
全部的资源将会经过REST的URI表示,操做经过HTTP动词表示,这可以覆盖全部能被执行且须要验证的操做。在下面的例子中,定义了三个角色:
order_manager: '/orders': - 'GET' - 'POST' - 'PUT' - 'DELETE' order_editor: '/orders': - 'GET' - 'POST' - 'PUT' order_inspector: '/orders': - 'GET'
因而可知,REST自然可以实现权限控制。经过处理传入请求,REST服务可以检索有价值的信息,这些信息能够移交给单独的模块以执行身份验证和受权。若是用户被受权在目标资源上执行所请求的方法,则能够继续请求处理。不然,在到达任何内部应用程序代码以前拒绝进一步访问。
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注个人微信公众号!将会不按期的发放福利哦~