1. 概述

权限管理,一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源。资源包括访问的页面,访问的数据等,这在传统的应用系统中比较常见。本文介绍的则是基于Saas系统架构的处理模型,SaaS应用的数据安全是目前大型企业比较担心的问题,因此,JSaaS的安全应用就显得非常重要。JSaaS平台不单是一款私有云的应用管理平台,更是一款可扩展开发的,适合于二次开发的租用的应用开发平台,如适合集团下有多个子公司多个子应用的开发。同时用于一个单位上使用,相当于只有一个租户的SaaS应用。本文从应用使用场景进行分析设计,并且基于Spring Security的开源安全框架上进行设计,以保证满足未来SaaS应用的数据安全要求。

2. Spring Security权限管理的原理

Spring Security 是一成熟的安全管理框架,大量应用于不同的系统中,其权限管理原理很简单,就是通过一组filter进行访问地址的拦截,通过判断用户的身份及其允许访问的权限,然后授权是否允许访问其下的资源。资源包括页面、逻辑代码中方法等。借用网上一图说明:

这些不同的Filter作用,请参考以下访问地址:

http://blog.163.com/yf_198407/blog/static/5138541120114272476265/

任何一个平台的数据访问都是需要授权的,授权只需要管理好两点,一是登录,另一个是授权访问需要的内容。Spring Security实现这两点非常容易,它已经提供了对应的接口及拦截点。

目前市面上大部分的平台都是基于角色控制访问的,因此,我们JSaas平台也是采用该办法,通过对角色或用户组进行授权,然后再把角色或用户组授权给用户即可,其原理图如下所示:

这些不同的Filter作用,请参考以下访问地址:

http://blog.163.com/yf_198407/blog/static/5138541120114272476265/

任何一个平台的数据访问都是需要授权的,授权只需要管理好两点,一是登录,另一个是授权访问需要的内容。Spring Security实现这两点非常容易,它已经提供了对应的接口及拦截点。

目前市面上大部分的平台都是基于角色控制访问的,因此,我们JSaas平台也是采用该办法,通过对角色或用户组进行授权,然后再把角色或用户组授权给用户即可,其原理图如下所示:

【说明】用户组包括的概念可以很广,如角色、部门、岗位、临时用户组等。我们在系统中只需要授权给用户组可访问哪一些资源,然后再把对应的用户组授权给对应的用户即可。为了后续以后平台对接其他用户的组织架构管理,我们对用户再进行一层隔离,即通过登录账号来实现登录的身份认证,而登录账号只需要通过关联用户即可。


 【用户、用户组、资源之间的关系】

3. JSaaS平台的权限设计要点

3.1. 登录--身份认证

平台上有登录权限的实体我们称之为用户账号,也称之为身份认证,Security只需要实现UserDetails接口即可,登录的时候调用一下Security的安全认证接口即可。如下所示:

<!-- 认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 --><security:authentication-manager alias="authenticationManager"><security:authentication-provider user-service-ref="userDetailsProvider" /></security:authentication-manager><bean id="userDetailsProvider" class="com.redxun.saweb.security.provider.UserDetailsProvider" />

UsesrDetailsProvider只需要实现UserDetailsService的loadByUsername(String username)方法即可,登录的实体实现UserDetails的方法即可。用户组实现GrantedAuthority接口即可。

虽然Spring Security提供了登录的实现Filter,但我们可以用它默认的实现,但为了我们平台的后续的更多扩展及灵活性,我们决定提供自定义的登录方式,但需要在登录后,通知Spring Security框架,即设置该框架需要的一些参数数据,以使得其后续可以通过对应的Filter访问到需要的资源。以下为我们的LoginController的实现方式:

@Controller
@RequestMapping("/")
public class LoginController extends BaseController{@ResourceAuthenticationManager authenticationManager;@ResourceLoginManager loginManager;@RequestMapping("login")@ResponseBodypublic JsonResult login(HttpServletRequest request,HttpServletResponse response) throws Exception{String username=request.getParameter("username");String password=request.getParameter("password");IUser user=loginManager.getLoginUser(username);if(user==null || !user.getUsername().equals(username) || !user.getPwd().equals(password.trim())){return new JsonResult(false,"密码或用户名不正确!");}if(user.getTenant()==null || !MStatus.ENABLED.toString().equals(user.getTenant().getStatus())){return new JsonResult(false,"企业机构已经被禁用!");}UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(username, password);authenticationManager.authenticate(token);SecurityContextHolder.getContext().setAuthentication(token);return new JsonResult(true,"Login Success");}
}

以上特别说明一下,是登录的时候,进行了用户所在的账号的检查,以决定是否允许用户进入平台,当检查用户存在,并且密码也正确,然后产生一个带用户或及密码的令牌给Spring Security框架,让它通过后续的登录验证,否则后面的其他拦截器还是会进行拦截不允许用户访问。

3.2. 资源访问控制

3.2.1. 系统资源存储

平台上展示出来的页面、数据、按钮、后台允许访问的业务逻辑我们统一称之为系统资源,这些系统资源我们需要进行授权访问,以保证系统的安全性。那么我们如何来管理这些资源,这就需要我们进行系统的资源访问控制的设计。

平台上采用Spring MVC作为前端的控制框架,前端借用MiniUI来进行展示,因此,我们系统上的各种资源均可以用URL来表示,如下所示:

这些菜单下若有对应具体的功能及数据时,即带有具体的URL,这些URL对应的可以是具体的数据、也可以是操作按钮。以上图所示,系统中的资源包括:

  • 菜单

  • 按钮

  • 页面或数据

  • 子系统

【说明】

平台上除了具体的数据管理以外,其他的配置均可以在菜单管理中完成,包括管理机构下的非SaaS菜单以下SaaS菜单的管理。我们均把这些资源的数据存于SysMenu表中,以实现系统的资源的统一管理,同时为了兼顾系统的菜单展示模式,我们对菜单进行了树型的管理。


 【子系统表结构】


 【子菜单数据表结构】

3.2.2. 基于Spring Security上的扩展点:

用户登录后,需要对用户访问的资源进行安全拦截认证,我们通过在Spring Security的Filter Chain中增加我们的Filter,如下代码中的红色部分显示,在我们的Filter中,实现以下的功能要求即可:

<security:http  entry-point-ref="authenticationProcessingFilterEntryPoint"><security:intercept-url pattern="/login.do" access="ROLE_ANONYMOUS"/><security:intercept-url pattern="/register.do" access="ROLE_ANONYMOUS"/><security:intercept-url pattern="/captcha-image.do" access="ROLE_ANONYMOUS"/><security:intercept-url pattern="/pub/**" access="ROLE_ANONYMOUS"/><security:intercept-url pattern="/**" access="ROLE_PUB" /><security:logout invalidate-session="true" logout-success-url="/login.jsp" logout-url="/j_spring_security_logout"/><!--security:remember-me token-validity-seconds="3600" /--><security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="securityInterceptorFilter" /><security:custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" /></security:http><bean id="securityInterceptorFilter" class="com.redxun.saweb.filter.SecurityInterceptorFilter"><property name="securityDataProvider" ref="securityDataProvider"/></bean><bean id="securityDataProvider" class="com.redxun.saweb.security.provider.SecurityDataSourceProvider"><property name="sysMenuManager" ref="sysMenuManager"/><property name="anonymousUrls"><set><value>/login.do</value><value>/captcha-image.do</value><value>/register.do</value><value>/activeInst.do</value><value>/pub/anony/imageView.do</value><value>/pub/anony/imgUploadDialog.do</value><value>/pub/anony/upload.do</value><value>/pub/anony/previewImage.do</value><value>/pub/anony/imageView.do</value><value>/pub/anony/sysInst/regSuccess.do</value></set></property><property name="publicUrls"><set><value>/index.do</value></set></property></bean>

SecurityInterceptorFilter完成以下几件重要的资源控制访问要点,用户的权限控制都包含在这个过滤器中。

  • 如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。

  • 如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。

  • 如果用户已登录,也具有访问当前资源的权限,则放行。

3.2.3. 如何判断用户的访问资源的权限

我们需要清楚,如何通过当前登录的身份信息及拥有的用户组或角色,结合当前的访问URL,判断系统是否允许用户访问该URL。若允许,则放行,否则就抛出AccessDeniedException。

那如何通过拿到这两块信息来判断用户是否有访问资源的权限,这要求我们必须建议权限的统一数据中心,通过它来决定当前用户是否有权限访问。在此,我们在平台上建立了一个统一的数据中心,为了简化查询,我们通过HashMap来构造这个数据中心,其结构如下所示:

URL

用户组ID

/sys/core/subsys/list.do

1,2,3

/sys/core/subsys/del.do

2,3,5

/sys/core/subsys/save.do

1,2,3

/sys/core/sysMenu/save.do

4,5,8,10,22

/sys/core/sysMenu/del.do

1,2

说明:该数据中心在Spring容器启动时进行构建,并且会进行缓存,当权限数据进行更新时,需要更新该数据中心的数据。

其判断逻辑如下所示:


 其逻辑实现的代码如下所示:

@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain chain) throws ServletException, IOException {String url=request.getRequestURI();//若有contextPath,则切出来if(org.springframework.util.StringUtils.hasLength(request.getContextPath())){String contextPath=request.getContextPath();int index=url.indexOf(contextPath);if(index!=-1){url=url.substring(index+contextPath.length());}}Authentication auth= SecurityContextHolder.getContext().getAuthentication();//取得认证器//是否包括在匿名访问的地址中if("anonymousUser".equals(auth.getPrincipal().toString())){if(securityDataProvider.getAnonymousUrls().contains(url)){doFilter(request, response, chain);return;}response.sendRedirect(request.getContextPath()+"/login.jsp");return;}IUser user=ContextUtil.getCurrentUser();//登录完成后,需要Spring后续的Filter进行处理if(user==null){doFilter(request, response, chain);return;}//是否为超级管理员boolean isSuperUser=false;//是否为管理机构的超级管理员if(WebAppUtil.isSaasMgrUser() && user.getUsername().startsWith("admin@")){isSuperUser=true;}//若为超级管理员,则允许访问if(isSuperUser){doFilter(request, response, chain);return;}//是否为租户管理员//允许访问所有的Saas菜单地址if(user.getUsername().startsWith("admin@")){if(securityDataProvider.getTenantUrlSet().contains(url)){doFilter(request, response, chain);return;}}//公共URLif(securityDataProvider.getPublicUrls().contains(url)){doFilter(request, response, chain);return;}//如果不包括在配置的菜单访问地址中,则默认允许访问if(!securityDataProvider.getMenuGroupIdsMap().containsKey(url)){doFilter(request, response, chain);return;}Set<String> groupIdSet=securityDataProvider.getMenuGroupIdsMap().get(url);boolean isIncludeGroupId=false;for(GrantedAuthority au:auth.getAuthorities()){if(groupIdSet.contains(au.getAuthority())){isIncludeGroupId=true;break;}}if(!isIncludeGroupId){throw new AccessDeniedException("Access is denied! Url:" + url + " User:" + SecurityContextHolder.getContext().getAuthentication().getName());}//进行下一个Filterchain.doFilter(request, response);}

从上面的实现的代码可以看到,关键是需要建立统一的权限数据中心,用户的权限认证只需要从中查找到匹配的用户ID即可,否则抛出禁止访问的异常。

4.数据库表的设计要素

4.1. 关于SaaS的租户表设计

JSaaS平台跟传统平台的一大区别是其引入租户的概念,我们把租户理解为使用平台的独立机构,该机构有独立的组织架构,在现行的中国法律中我们可以理解为有独立组织机构代码证的社会团队,如单位、

公司等。对于大型的集团公司,其下每个分公司也可以在使用本平台上,我们也可以用租户的概念来区分,即他们进入平台中使用功能及数据都是独立于其他租户的数据。为了适应小至中大型企业的不同运营的要求,我们采用的是共享数据库+独立数据库的方式来实现企业的不同云应用的需求。

当企业为比较大型,数据量比较大,这时我们可采用PAAS的方式为该企业提供独立的运行空间,数据库也将独立,即可认为其只有一个租户或几个相关的租户(如带有几个分公司的方式),这时对企业的数据安全是有非常有保障,也可以打消企业对自己的一些敏感数据的安全的一些顾虑。

当企业比较小时或数据量不多时,可以在平台上注册成为租户,即可以使用平台上的所有服务,这时不需要投入太多的资金,即可以实现企业的信息化管理,这种模式对中小企业是有吸引力的。

【说明】租户是由平台的管理机构实现统一管理,因此,其功能只是对平台运营商开放,不对租户开放该功能。

4.2. 组织架构设计

平台简化组织架构的管理,但又能适应复杂的组织架构管理需求,我们把人员的组织架构进行了如下方式的划分

 1. 组织架构实体

  • 用户组

为了管理不同的用户组,平台提供了用户组的维度管理,通过这种方式可以有效根据业务 需求对自己的用户组及用户进行不同的分类划分。

  • 用户

    平台的用户,可以理解平台的使用人员

 2. 实体关系管

为了对组织架构的实体进行维护管理以满足业务对组织架构的要求,系统提供了对他们的关系维护管理,如最常见的关系就是从属关系,即用户组中包括了哪一些用户,用户组的负责人是谁。再者复杂的是每个用户的上级用户,或某项业务的汇报领导是谁。这些可以通过关系的定义可以灵活实现。

a)用户与用户关系

实现用户与用户的关系定义,如我的直属领导,通过定义这种关系,可以为某个用户设置其直属领导是谁。

b)用户与用户组关系

定义用户与用户组的关系,如部门的领导,片区的负责人。这些均可以称之为用户与组的关系,通过定义这些关系,可以有效管理用户组下的用户。

c)用户组与用户组的关系

定义用户组与用户组的关系在某些应用场景也会采用,如职务、部门。我们把挂在部门下的职务称之为岗位,通过岗位可以快速定位其属于哪个部门。

4.3. 系统权限涉及的表设计

表名

作用

OS_USER

用户表

SYS_ACCOUNT

用户的账号表

OS_GROUP

用户组表,如部门、角色、岗位等,可为树型结构

OS_DIMENSION

用户组维度,用于定义用户组的分类

SYS_MENU

系统的菜单的资源,包括可访问的菜单、URL等

SYS_SUBSYS

子系统

OS_GROUP_SYS

用户组下授权访问的子系统

OS_GROUP_MENU

用户组下授权访问的菜单

OS_REL_TYPE

关系定义,包括各种用户关系、用户组关系、用户与用户的关系定义

OS_REL_INST

关系实例表,存储各种关系,如用户从属于部门,需要从该表查询

5.关于SaaS的授权的扩展关键用例

平台把用户分为以下几方面,从管理的用例如下:

平台有一个比较重要的是SaaS管理员,它可以管理所有租户的信息,包括组织架构调用。当然为了数据安全,可以关闭一些对应的管理功能。

具体的访问效果如:

http://www.redxun.cn:8020/saweb/login.jsp

http://www.redxun.cn/?p=698    开发框架内容

基于Spring Security 的Java SaaS应用的权限管理相关推荐

  1. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离

    在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与权限管理. ...

  2. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  3. java oauth sso 源码_基于Spring Security Oauth2的SSO单点登录+JWT权限控制实践

    概 述 在前文<基于Spring Security和 JWT的权限系统设计>之中已经讨论过基于 Spring Security和 JWT的权限系统用法和实践,本文则进一步实践一下基于 Sp ...

  4. 基于 Spring Security 的开源统一角色访问控制系统 URACS

    URACS Java语言开发的统一角色访问控制系统(Unified Role Access Control System),基于Spring Security 3实现的权限控制系统 程序框架版本说明: ...

  5. 基于Spring Security角色的访问授权示例

    Today we will look into spring security role based access and authorization example. However before ...

  6. 基于Spring Security和 JWT的权限系统设计

    2019独角兽企业重金招聘Python工程师标准>>> 写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会 ...

  7. 基于Spring Security与JWT实现单点登录

    基于RBAC的权限管理 RBAC(Role-Based Access Control):基于角色的访问控制 当前项目中,RBAC具体的表现为: 管理员表:ams_admin 角色表:ams_role ...

  8. 基于Spring Security实现权限管理系统

    基于Spring Security实现权限管理系统 稍微复杂一点的后台系统都会涉及到用户权限管理.何谓用户权限?我的理解就是,权限就是对数据(系统的实体类)和数据可进行的操作(增删查改)的集中管理.要 ...

  9. 基于Spring boot的Java开源商城系统,简直太香了

    前言 一个基于spring boot的JAVA开源商城系统,是前后端分离.为生产环境多实例完全准备.数据库为b2b2c商城系统设计.拥有完整下单流程和精美设计的java开源商城系统spring boo ...

最新文章

  1. java.lang.VerifyError
  2. Session——servlet
  3. .NET core3.0 使用Jwt保护api
  4. 闲来无事刷水题、简单博弈论专题、sg函数、洛谷
  5. Linux 格式化磁盘命令mkfs
  6. 股票型基金和期货有什么区别?
  7. Go语言程序的数组初始化
  8. python常用代码大全-Python 网络爬虫实战项目代码大全
  9. 第四十六讲 ASP.NET实例编程(五)
  10. java连接数据库的解决方法大全(mysql)
  11. java实验十三io_Java语言基础13—IO
  12. 坐标拾取器App上线
  13. 018 EPLAN 宏部件库 西门子 欧姆龙 三菱PLC窗口宏ema正泰edz数据 mdb(94G)
  14. 机器学习常用术语英语词汇
  15. IoU,GIoU,DIoU、CIoU详解
  16. 在 M1/M2 芯片的Mac上安装最新原生 ruby 的超简单方法(无需rvm)
  17. 实验吧安全杂项WP(一)
  18. windows密码破解(哈希破解技术)
  19. php phpstudy虚拟域名配置
  20. 角度与弧度之间的转换

热门文章

  1. php第三方阿里云接口
  2. 注册公众号(企业类型的订阅号)参考步骤
  3. 一个性能优化实操案例
  4. 计算机 窗口打开的方法,如何打开命令行窗口?两种实用的方法介绍
  5. CPU,GPU,NPU的架构差异对比
  6. Python # 扫描端口功能 # 获取网卡的Mac地址 # 局域网扫描器IP地址和MAC地址,获取网卡名称和其ip地址
  7. Uboot SPL的Boot模式选择(从MMC切换到SPI启动)
  8. 如何根据原理图画封装_如何快速设计元器件原理图库和PCB封装库?
  9. 一文精通S4 HANA中的Business Partner
  10. 如何破解excel密码