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{ @Resource AuthenticationManager authenticationManager; @Resource LoginManager loginManager; @RequestMapping("login") @ResponseBody public 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容器启动时进行构建,并且会进行缓存,当权限数据进行更新时,需要更新该数据中心的数据。
其判断逻辑如下所示:
其逻辑实现的代码如下所示:
@Override protected 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; } } //公共URL if(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()); } //进行下一个Filter chain.doFilter(request, response); }
从上面的实现的代码可以看到,关键是需要建立统一的权限数据中心,用户的权限认证只需要从中查找到匹配的用户ID即可,否则抛出禁止访问的异常。
4.数据库表的设计要素
4.1. 关于SaaS的租户表设计
JSaaS平台跟传统平台的一大区别是其引入租户的概念,我们把租户理解为使用平台的独立机构,该机构有独立的组织架构,在现行的中国法律中我们可以理解为有独立组织机构代码证的社会团队,如单位、
公司等。对于大型的集团公司,其下每个分公司也可以在使用本平台上,我们也可以用租户的概念来区分,即他们进入平台中使用功能及数据都是独立于其他租户的数据。为了适应小至中大型企业的不同运营的要求,我们采用的是共享数据库+独立数据库的方式来实现企业的不同云应用的需求。
当企业为比较大型,数据量比较大,这时我们可采用PAAS的方式为该企业提供独立的运行空间,数据库也将独立,即可认为其只有一个租户或几个相关的租户(如带有几个分公司的方式),这时对企业的数据安全是有非常有保障,也可以打消企业对自己的一些敏感数据的安全的一些顾虑。
当企业比较小时或数据量不多时,可以在平台上注册成为租户,即可以使用平台上的所有服务,这时不需要投入太多的资金,即可以实现企业的信息化管理,这种模式对中小企业是有吸引力的。
【说明】租户是由平台的管理机构实现统一管理,因此,其功能只是对平台运营商开放,不对租户开放该功能。
4.2. 组织架构设计
平台简化组织架构的管理,但又能适应复杂的组织架构管理需求,我们把人员的组织架构进行了如下方式的划分
1. 组织架构实体
-
用户组
为了管理不同的用户组,平台提供了用户组的维度管理,通过这种方式可以有效根据业务 需求对自己的用户组及用户进行不同的分类划分。
-
用户
平台的用户,可以理解平台的使用人员
相关推荐
在这个项目中,Spring Security将被用来管理用户登录、权限验证以及防止未经授权的访问。 2. **多租户架构**:在SaaS应用中,多租户架构意味着单个实例可以服务于多个独立的客户(租户),每个租户有自己的数据和...
资源权限管理 通知推送中心(短信、邮件) 错误码中心(查询错误码,大概产生原因,解决措施、热门错误码统计) 知识库(记录常见问题排查方式等) 在线 api 文档中心 核心框架 SpringBoot SpringCloud Shoulder ...
Pre基于Spring Boot 2.2.2、Mybatis Plus、Spring Security 5.2.1、Vue的前后端分离的的RBAC权限管理系统,项目支持数据权限管理,支持后端配置菜单动态路由,Spring Social实现第三方社交登录, SaaS多租户模式,努力...
通过配置,Spring Security可以实现认证(Authentication)和授权(Authorization),对用户的登录、权限分配、会话管理等进行精细控制。 【企业权限管理】 企业权限管理是系统的核心部分,它涉及到用户角色分配、...
Spring Boot:用于快速开发基于Java的后端服务。 Apache Shiro或Spring Security:用于安全和认证。 Thymeleaf或JSF:用于构建Java Web应用的用户界面。 数据库:如MySQL、PostgreSQL或MongoDB。 开发优势 实用性:...
1. **RuoYi-Vue简介**:RuoYi-Vue是一款基于Vue.js和Element UI的后台管理框架,提供了登录、权限管理、菜单动态路由等功能,便于开发者快速搭建企业级应用。 2. **集成环境**:通常RuoYi-Vue项目已经集成了...
本RuoYi-Vue Pro后台管理系统基于...系统实现了基于Spring Boot、MyBatis Plus、Vue和Element的后台管理系统以及微信小程序,支持RBAC动态权限、数据权限和SaaS模式。界面友好,功能完善,适合用于企业级后台管理。
SaaS OA协同办公软件 v2.0 是一个基于 Java 的企业级应用程序,旨在为企业提供全面的办公协作解决方案。以下是该软件的主要实现描述: 模块化架构设计: 采用模块化设计思想,将不同功能模块拆分成独立的组件,如...
【标题】"Tomcat部署Web项目之Java版SaaS OA协同办公软件 v2.0-saas-oa",这是一篇关于如何在Tomcat服务器上部署基于Java开发的SaaS(Software as a Service)模式的OA(Office Automation)协同办公系统v2.0的文章...
Spring Security或者Apache Shiro可能被用来实现用户认证和授权,保护系统免受非法访问。 5. **协作与任务管理**:协同办公的核心功能包括任务分配、审批流程、日程管理等。这些功能可能通过工作流引擎如Activiti或...
【标题】"凯撒JAVA版SaaS OA协同办公软件 v2.0_saas-oa.rar" 是一个基于Java技术开发的协同办公系统,主要用于企业或组织的信息化管理。SaaS(Software as a Service)模式意味着该软件是通过互联网提供服务,用户...
总结,【信息办公】凯撒java版SaaS OA协同办公软件 v2.0_saas-oa.zip是一个基于JSP和Java技术构建的SaaS应用,集成了多种协同办公功能,如用户管理、工作流、文档管理等。其源码可以作为学习和参考,理解如何利用JSP...
安全性方面,系统可能利用HTTPS协议保证数据传输的安全,同时采用Spring Security等框架进行权限管理和认证。 总结来说,"JSP源码 凯撒java版SaaS OA协同办公软件 v2.0_saas-oa.rar"这个压缩包中包含了基于Java和...
Java springBlade微服务开发平台 是一个由商业级项目升级优化而来的微服务架构,采用Spring Boot 2.6 、Spring Clou,用前后端分离的模式,前端开源两个框架:Sword (基于 React、Ant Design)、Saber (基于 Vue、...
【信息办公】凯撒java版SaaS OA协同办公软件 v2.0_saas-oa.rar是一款基于Java技术的SaaS模式协同办公应用软件,适用于企业信息化建设,旨在提高办公效率和管理水平。SaaS(Software as a Service)模式是云计算服务...
一个基于Java的多租户后端管理系统可能使用Spring Boot作为基础框架,Spring Data JPA处理数据访问,MyBatis或Hibernate作为ORM工具,Redis或Memcached用于缓存,以及Thymeleaf或FreeMarker作为模板引擎。...
这是一个基于Java和Spring Boot技术构建的微信小程序商城项目,包含了SAAS(Software as a Service)架构和前后端的完整源码。此项目旨在提供一种云端部署的解决方案,使得商家能够快速搭建自己的在线商城,实现商品...
可能会用到Spring Security或Apache Shiro进行权限控制,防止未授权访问。 5. **分布式与云计算**:作为SaaS应用,该系统可能部署在云环境中,利用负载均衡、分布式缓存(如Redis)以及消息队列(如RabbitMQ)来...
同时,Spring Security或者OAuth2可以用于实现权限管理和认证,确保系统安全。 MyBatis Plus是MyBatis的增强工具,它在MyBatis的基础上做了很多自动化工作,如自动填充主键、自动生成SQL语句、支持Lambda表达式等,...
5. 安全性考虑:引入Spring Security或Apache Shiro等安全框架,保障用户登录验证和权限控制。 6. 云服务集成:考虑采用SaaS(Software as a Service)模式,将系统部署到云端,提高可扩展性和易用性。 四、工作...