七叶笔记 » java编程 » Spring Security权限管理实现接口动态权限控制

Spring Security权限管理实现接口动态权限控制

SpringBoot实战电商项目mall(30k+star)地址:https://github.com/macrozheng/mall

摘要

权限控管理作为后台管理系统中必要的功能,mall项目中结合Spring Security实现了基于路径的动态权限控制,可以对后台接口访问进行细粒度的控制,今天我们来讲下它的后端实现原理。

前置知识

学习本文需要一些Spring Security的知识,对Spring Security不太了解的朋友可以看下以下文章。

mall整合SpringSecurity和JWT实现认证和授权(一) mall整合SpringSecurity和JWT实现认证和授权(二)仅需四步,整合SpringSecurity+JWT实现登录认证!

数据库设计

权限管理相关表已经重新设计,将原来的权限拆分成了菜单和资源,菜单管理用于控制前端菜单的显示和隐藏,资源管理用来控制后端接口的访问权限。

数据库表结构

其中ums_admin、ums_role、ums_admin_role_relation为原来的表,其他均为新增表。

数据库表介绍

接下来我们将对每张表的用途做个详细介绍。

ums_admin

后台用户表,定义了后台用户的一些基本信息。

ums_role

后台用户角色表,定义了后台用户角色的一些基本信息,通过给后台用户分配角色来实现菜单和资源的分配。

ums_admin_role_relation

后台用户和角色关系表,多对多关系表,一个角色可以分配给多个用户。

ums_menu

后台菜单表,用于控制后台用户可以访问的菜单,支持隐藏、排序和更改名称、图标。

ums_resource

后台资源表,用于控制后台用户可以访问的接口,使用了Ant路径的匹配规则,可以使用通配符定义一系列接口的权限。

ums_resource_category

后台资源分类表,在细粒度进行权限控制时,可能资源会比较多,所以设计了个资源分类的概念,便于给角色分配资源。

ums_role_menu_relation

后台角色菜单关系表,多对多关系,可以给一个角色分配多个菜单。

ums_role_resource_relation

后台角色资源关系表,多对多关系,可以给一个角色分配多个资源。

结合Spring Security实现

实现动态权限是在原mall-security模块的基础上进行改造完成的,原实现有不清楚的可以自行参照前置知识中的文档来学习。

以前的权限控制

以前的权限控制是采用Spring Security的默认机制实现的,下面我们以商品模块的代码为例来讲讲实现原理。

首先我们在需要权限的接口上使用@PreAuthorize注解定义好需要的权限;

然后将该权限值存入到权限表中,当用户登录时,将其所拥有的权限查询出来;

之后Spring Security把用户拥有的权限值和接口上注解定义的权限值进行比对,如果包含则可以访问,反之就不可以访问;

但是这样做会带来一些问题,我们需要在每个接口上都定义好访问该接口的权限值,而且只能挨个控制接口的权限,无法批量控制。其实每个接口都可以由它的访问路径唯一确定,我们可以使用基于路径的动态权限控制来解决这些问题。

基于路径的动态权限控制

接下来我们详细介绍下如何使用Spring Security实现基于路径的动态权限。

首先我们需要创建一个过滤器,用于实现动态权限控制,这里需要注意的是doFilter方法,对于OPTIONS请求直接放行,否则前端调用会出现跨域问题。对于配置在IgnoreUrlsConfig中的白名单路径我也需要直接放行,所有的鉴权操作都会在super.beforeInvocation(fi)中进行。

在DynamicSecurityFilter中调用super.beforeInvocation(fi)方法时会调用AccessDecisionManager中的decide方法用于鉴权操作,而decide方法中的configAttributes参数会通过SecurityMetadataSource中的getAttributes方法来获取,configAttributes其实就是配置好的访问当前接口所需要的权限,下面是简化版的beforeInvocation源码。

知道了鉴权的原理,接下来我们需要自己实现SecurityMetadataSource接口的getAttributes方法,用于获取当前访问路径所需资源。

由于我们的后台资源规则被缓存在了一个Map对象之中,所以当后台资源发生变化时,我们需要清空缓存的数据,然后下次查询时就会被重新加载进来。

这里我们需要修改UmsResourceController类,注入DynamicSecurityMetadataSource,当修改后台资源时,需要调用clearDataSource方法来清空缓存的数据。

之后我们需要实现AccessDecisionManager接口来实现权限校验,对于没有配置资源的接口我们直接允许访问,对于配置了资源的接口,我们把访问所需资源和用户拥有的资源进行比对,如果匹配则允许访问。

我们之前在DynamicSecurityMetadataSource中注入了一个DynamicSecurityService对象,它是我自定义的一个动态权限业务接口,其主要用于加载所有的后台资源规则。

接下来我们需要修改Spring Security的配置类SecurityConfig,当有动态权限业务类时在FilterSecurityInterceptor过滤器前添加我们的动态权限过滤器。

这里在创建动态权限相关对象时,还使用了@ConditionalOnBean这个注解,当没有动态权限业务类时就不会创建动态权限相关对象,实现了有动态权限控制和没有这两种情况的兼容。

这里还有个问题需要提下,当前端跨域访问没有权限的接口时,会出现跨域问题,只需要在没有权限访问的处理类RestfulAccessDeniedHandler中添加允许跨域访问的响应头即可。

当我们其他模块需要动态权限控制时,只要创建一个DynamicSecurityService对象就行了,比如在mall-admin模块中我们启用了动态权限功能。

权限管理功能演示

具体参考:大家心心念念的权限管理功能,这次安排上了!

mall项目更新源码地址 https://github.com/macrozheng/mall

以上就是Spring Security权限管理实现接口动态权限控制的详细内容,更多关于Spring Security接口动态权限控制的资料请关注七叶笔记其它相关文章!

相关文章