APP下载

基于RBAC的通用权限管理系统

2020-12-28何鼎权胡辉严家成

电脑知识与技术 2020年33期

何鼎权 胡辉 严家成

摘要:权限管理功能是信息管理系统的主要功能之一,是系统功能的不可或缺的部分,任何一个信息管理系统都涉及权限管理的核心功能。通用安全的权限管理系统,保证管理信息系统的安全性是特别重要的。基于角色的访问控制( Role-Base Access Control.RBAC)模型,以满足不同系统的建设需求,其优势在于角色与权限之间的变化比用户与权限之间的变化更加稳定,拥有较高的安全机制保护系统安全和有效提高系统开发效率。

关键词:权限管理功能;权限控制;RBAC

中图分类号:TP311 文献标识码:A

文章编号:1009-3044(2020)33-0097-02

开放科学(资源服务)标识码(OSID):

1 基于角色的访问控制

传统的权限管理功能设计具有固定不变的特点,然而不同的系统之间资源具有差异性,一个权限系统无法在其他系统中通用,所以传统无法保留快速灵活地响应企业或机构中影响要素的变化,权限控制部分需要进行重新设计,以满足不同系统的需求,因此造成时间和资源的浪费[1]。采用基于角色的访问控制方法(RBAC)相对于强制或自主访问控制方法,其优势在于角色与权限之间的变化比用户与权限之间的变化更加稳定,减少了授权的复杂性,降低了出錯的概率,并且RBAC能够根据需求的变动,拥有较高的安全机制保护系统安全。

2 RBAC模型

RBAC模型使用户和权限分离,用户被赋予相应的角色而获得角色的权限,从而减少了权限管理的复杂度[2]。在RBAC之中,用户和角色之间可以是多对多的关系,即一个用户在不同场景下是可以有不同的角色。包含用户、角色、目标、操作、权限五个基本数据元素,用户和权限被分离独立开来,使得权限的授权认证更加灵活[3]。

3 系统分析与设计方案

3.1身份认证

当用户没有先执行登录操作,无法使用权限管理系统,会被Shiro安全模块阻止访问一切资源,待身份验证成功后,才可以使用权限管理系统,Shiro安全模块接收到用户的用户名和密码后,与数据库中的用户账号和密码相对应的做比对,若验证成功则进入管理系统主页面,否则给出错误信息并返回登录界面反馈给登录用户。

当用户身份验证成功后,Shiro内置的Session对象会存储用户的身份信息。每一个用户持有的Session对象完全独立的,互不影响并且Session对象在用户离开网址前一直有效[4],在该对象中,也包含了用户的时间戳,上次登录时间,最后操作时间等信息,因此在各个用户的相关信息显示到在线用户模块中,单独地在系统的某一个模块中给其他用户查看。当用户退出系统后,该用户持有的session对象将会失效,用户必须重新登录后才能再次显示到在线用户模块中,并再次使用权限管理系统。

3.2 角色赋予

通过对用户赋予某种角色,角色对应一个或多个相应的权限以访问或操作某些资源。本系统主要的授权的方式有两种:直接授予角色和临时授予角色。

直接授予角色:通常意义来说赋予角色某种权限,此角色拥有该角色所包含所有的权限,拥有该角色的用户则拥有了该角色所有的权限,具有自动访问的特性。

临时授予角色:用户临时拥有某种角色,不会新增加角色,时间过后用户拥有的临时角色就无法拥有该项临时资源,增加了权限赋予的灵活性。

3.3 过滤链设计

Shiro安全模块中过滤链的设计是最复杂也是最重要的模块,过滤链主要是针对用户请求URL进行安全检查,看用户符合过滤链对应的相应策略,判断是否有相应权限访问某一资源。由于采用的Shiro框架,因此使用内置对象基于Servlet模式的过滤器filter Chain Definitions,在该对象中可以进行安全控制哪些是用户可以访问的,对于哪些用户是不能给用户访问的。对应用户不能访问的资源程序员不能把相应资源调转使用。例如,对应的验证码图片、js样式、登录页面是可以匿名访问的,根据需求设计过滤链。Shiro可以根据访问路径配置不同的过滤器,在本系统中主要使用的过滤名称为authc、anon以及自定义的过滤器,在过滤器中提供策略。

3.4 日志输出

系统需要将日志数据输出到指定位置保存起来,尤其是权限管理系统,对于日志数据尤为重要。其中log4j日志框架能根据日志级别将日志数据输出,如以iO操作方式,写数据到文本文件、数据库中或console窗口,功能强大。

3.5 Websocket

服务器和客户端进行推送和发送数据在信息管理系统中必不可少。相对于客户端对服务器发出HTTP协议请求并返回最新的数据给客户端的浏览器。这种模式具有请求可能包含较长的头部明显的缺点。而Websocket服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,数据格式比较轻量,性能开销小,通信高效,毫无疑问这样会节省很多的带宽等资源。在WebSocket中,浏览器和服务器只需要做一个握手的动作就形成了一条快速通道。服务器和客户端之间没有同源限制,客户端可以与任意服务器通信并直接数据互相传送[5]。

3.6 数据库连接池

C3p0,由程序启动时建立足够的数据库连接池,由程序动态地负责分配、管理和释放数据库连接。

3.7 前端页面

iQuery EasyUI、jstl标签库。

4 系统总体流程图

5 系统实现

5.1 历史记录模块

对于日志模块的设计方案,shiro安全模块在监控web应用的过程中,可以使用AOP编程对用户的一些行为进行日志记录,安全模块一直存在整个web应用中,通过AOP编程不需要写重复的日志代码,但是在本系统中使用的是典型的log4j日志,程序员只需要按照日志模块的方法名称匹配规则来写相关方法,日志就会自动添加,对日志也可以设计输出策略和模式,在当前系统中输出io流的方式到前端页面,采用的是websocket传输,将用户记录传输到页面给用户查看。极大方便系统的灵活性和便利性。

5.2 认证模块

系统需要根据用户的信息判断对应用户拥有哪些权限,认证模块必不可少。当用户登录权限系统,系统拦截到用户发出的登录URL,读出登录表单的认证信息,把它交给表单认证过滤器,让表单认证过滤器和验证者进行对比,实现用户的认证。表单认证过滤器中包含了用户名、密码、主机信息、验证码信息。在认证的过程中,实现了以下功能:

1)当用户在没有注销的情况下,如果在另一台机器上重新登录,将重置实时登录信息,并通知原登录机器断开连接。

2)对登录成功的用户,将用户的所属用户组以及所属的部门信息等进行更新。

3)对用户发出的登录URL进行认证,通过对密码进行MD5加密比对判断用户的登录信息是否正确。

4)对于自动授予角色进行逻辑判断并对数据的相关信息进行更新变动。

因为本身设计的策略模式和Shiro本身提供的策略不完全相同,因此通过继承相应的接口来实现需求的相关策略,如表单认证过滤器,继承表单认证过滤接口,改写内部的方法,使服务器接收需求所需要的信息。

5.3 授权模块

当前用户访问某项资源时,若用户拥有该角色对应的权限则允许访问,否则拒絕访问。在该模块中包含以下内容:

1)当前用户对应的角色赋予。

2)排他属性进行访问权限阻止的设定。

3)主机范围的判断。

4)临时角色和自动赋予角色的开启。

将角色和角色对应的权限放到Set集合中,在Shiro中有特定对象SimpleAuthorizationlnfo聚合授权信息,之后把用户信息包括权限信息读人到Subject中,提取Subject中的权限信息进行权限控制。如此用户就被赋予了角色对应的相关权限,进而访问对应的某些资源。

5.4 请求模块

当用户发送请求,携带url地址,Shiro对用户请求URL进行安全检查,看用户是否有相应权限访问某- URL。在请求安全模块设计中采用过滤链。这些过滤器拦截对应用系统的请求,并且在应用系统真正处理请求之前将这些请求转给shiro验证管理器和决策管理器处理从而强制安全性。Springmvc提供了前端控制器Dispatcher Servlet接收到用户请求,前端控制器根据用户请求相关信息来决定选择哪个Controller页面控制器,在对应函数中设计控制业务处理,处理完毕后返回一个Mode-IAndView(模型数据和逻辑视图名)。根据返回的逻辑视图名并把模型数据传人以便视图渲染展示。将结果响应返回给用户。如登录时,当账号密码不正确时.返回错误信息,当验证码不正确时,返回验证码错误,当登录成功时,返回登录信息。又如当没有权限时返回无权限,认证失败时返回权限认证失败信息。

5.5 其他模块

权限系统的设计是为了访问资源,因此本权限管理系统中设计了很多种模块。并系统地进行了角色设计、数据库设计、功能设计。如:部门模块、用户组模块、在线用户模块、角色模块、权限模块、临时角色模块、地址模块、用户模块、历史记录等相关资源模块提供给用户进行访问[6]。对象关系映射框架Hi-bernate在POJO与数据库表建立映射关系以及表与表之间多对多或一对多等的联系上,还有HQL语言,对数据库进行CURD操作、用来绑定查询参数、限制查询记录数量,并最终执行查询操作等等提供了很好的方式。Hibernate同时支持批量操作和级联操作,当增添/删除/修改时,可以设定增添删除/修改的级联信息,这给系统很好的维护性和程序员很大的方便性。下列展示其中一部分模块。

6 关键技术

Apache Shiro安全框架、Hibernate框架为本系统的关键技术。

6.1 Apache Shiro安全框架对本系统的安全性进行认证和授权,如下为简述的关键代码

1)验证代码

//验证,token包含了用户的相关信息

protected Authenticationlnfo doGetAuthenticationlnfo(Au-thenticationToken token) throws AuthenticationException(

//获取到用户的身份

String PrincipaI=(String) token.getPtincipal0;

//查询数据库,假设为从数据库查到的名字为zhangsan

if(!userCode.equals(”zhangsan”))

{ return null;

//账号不存在,直接放回账号和密码错误

}

String password=”lc4d234e3d8307ba8c4c5bd62f'8f2fc5”;//从数据库查到被加密的密码

String password=”1”;//用户请求发到服务器的密码

String salt=”hdquan”;//MD5加密的盐

//将用户账号、密码、加密的盐给验证管理器进行验证

return SimpleAuthenticationlnf'o(Principal, password, Byte-Source.Util.bytes(salt), this.getName());

//授权

protected Authorizationlnfo doGetAuthorizationInfo(Principal-Collection principals) {

List

Departmentpermissions=new

ArrayList0;

//权限增加 " department:create "

Departmentpermissions.add(" department:create ");

//,權限增加" department:add"

Departmentpermissions.add(" department:add ' ');

return SimpleAuthorizationlnf00. addStringPermissions(De-partmentpermissions);

}

for(Session session:activeSessions){

Object attribute = session.getAttribute(DefaultSubjectCon-text.PRINCIPALS_SESSION_KEY);

if(userCode.equals(String.valueOf(attribute》)

{

session.setTimeout(O);//设置嚣 session 立即失效 , 即将其踢

break;

}

for(Session session:sessionDAO.getActiveSessions O) {

if(String. valueOf( session. getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY》!=null

&& ! " null".equals(String.valueOf( session.getAttribute(Default-Subj ectContext.PRIN CIPALS_SESSION_KE Y》》

{

//判断上一个该请求的用户是否在线--不在线

if(String. valueOf(session. getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)

. equals(servletContext. getAttribute("User_Rejection_attri-bute ' '+parameter》

llservletContext. getAttribute(' ' User_Rej ection_attribute ' ' +pa-rameter)==null) {

if(SecurityUtils. getSubject0. hasRole(parameter》 {

if(String. valueOf(session. getAttribute(DefaultSubjectContext. PRIN-CIPALS_SESSION_KEY》

.equals《String)SecurityUtils.getSubj ectO.getPrincipal0)) {

MDC. put("User_Rejection_attribute", (String)SecurityUtils.getSubjectO.getPrincipal0);

log.info(使用用户排他性属性成功! ");

Obj ect obj ect= MDC.get("User_Rejection_attribute");

servletContext. setAttribute("User_Rejection_attribute" +pa-rameter, obj ect);//排他属性角色

parameter :

UserExclusiveRoleList.add(parameter);

servletContext. setAttribute("UserExclusive", UserExclu-siveRoleList);

return true;

}lelse{

MD C.put(”User_Rejection_attribute”,”当前用户名:”+(String)SecurityUtils.getSubj ect ().getPrincipal0);

log.info(”对不起,您没有该角色权限);

return false;

}lelse{

MD C.put( "User_Rej ection_attribute”,”当前使用用户排他属性用户名:”+servletContext. getAttribute(User_Rej ection_attri-bute "+parameter));

log.info(”对不起,当前有用户使用用户排他属性”);

return false;

}}

5)资源的权限管理与各类管理器的配置

@GenericGenerator(name = "user", strategy = "assigned")

private String userid;

private String reaIName;

private String sex;

private String postalCode;

@ManyToOne(cascade= {CascadeType. REFRESH, Casca-deType.PERSIST, C ascadeType.MERGE })//多对一

private Department department;

@ManyToMany(fetch=FetchType. EAGER, cascade={Casca-deType. REFRESH, CascadeType. PERSIST, CascadeType.MERGE})//多对多的关系,级联更新、级联持久化、级联合并

private Set roles=new HashSet0;

@ManyToOne(cascade={CascadeType. REFRESH, Casca-deType.PERSIST, CascadeType.MERGE))

private UserGroup userGroup;

private String usercode;

private String username;

}

6.3 登录请求与错误信息的反馈

@Controller

public class LoginController{

@RequestMapping(path= "/login.action")

public String login(HttpServletRequest req, HttpServletRe-sponse response) throws Exception

{

String shiroLoginFailure=(String) req. getAttribute("shi-roLoginFailure");

response.setCharacterEncoding(“utf-8”);

response.setHeader(" Content-Type", "text/html");

if(shiroLoginFailure! =null)

{

if(UnknownAccountException. class. getName0. equals(shi-roLoginFailure》

{

req.setAttribute("msg",”账号不正确”);

else if(IncorrectCredentialsException.class.getNameO.equals(shiroLoginFailure》

{

req.setAttribute("msg",”用户名/密码不正确”);

else if( "randomCodeError" .equals(shiroLoginFailure》

req.setAttribute("msg",”验证码错误不正确”);

else

{

req.setAttribute("msg",”登录失败”);

return”/login.j sp”;

@RequestMapping(”first.action”)

public String first(HttpServletResponse response) throws 10-Exception

return”redirect:/first.jsp”;

7 结束语

随着网络技术的发展和Intemet技術的普及,系统的权限问题越来越受到关注。本系统基于角色的权限管理模型,很好地减少授权管理的复杂性、支持网站的安全策略的灵活性,管理系统的易维护性和稳定性,降低了管理的开销。基于角色的权限管理模型对于日常分工细化的变化有很大的伸缩性。日常企业部门可以为系统增加新的角色并人新的功能时,可以在原有的基础上进行修改代码,就可以将新的功能集成到权限控制框架中,方便原有系统的开发和维护,而且这种权限控制方法针对分工细化的角色的变动,尤其在于日常用户或部门细化多的变动以后,将相关的角色中撤销,再赋予新的角色,给变动的用户或部门提供了很大的方便。

但本系统也有不足之处。如不能很好地解决并发请求的处理,当处于大量用户在线同时发出请求,会给中小型服务器造成阻塞状态,同时造成相关数据混乱从而导致脏数据出现,另外对于数据缓存的问题,没有很好的相关设置,这无疑会给系统和服务器造成很大的开销,这也是该系统需要改进的地方。最后本系统的代码冗余量存在一些不足。

参考文献:

[1]许向勇.B/S模式下基于RBAC的权限管理系统设计与实现[J].科技风,2009(21):262-263.

[2]倪东英,张晓丽.基于RBAC的用户权限管理的设计与实现[J].济南大学学报(自然科学版),2010,24(2):167-171.

[3]李辉,崔汉国,林积微,等.RBAC优化模型在装备保障信息系统中的应用[J].计算机工程与设计,2008,29(6):1450-1452,1481.

[4]马荣飞,统一身份认证系统的研究与实现[Jl.计算机工程与科学,2009,31(2):145-149.

[5]王勇,张艳艳,翟流顺.Web应用安全框架[J].科技信息,2008(35):492-493.

[6]陈继南,姜莹,孔祥荣.基于角色的Web信息系统权限管理方法[J].武汉理工大学学报(信息与管理工程版),2008,30(2):265-268.

【通联编辑:谢媛媛】

作者简介:何鼎权(2000-),男,广东河源人,本科在读,专业为网络工程;胡辉(1979-),女,江苏盐城人,讲师,硕士,研究方向为软构件技术、信息系统、ERP和团队管理;严家成(1973-),男,山东临沂人,专科,研究方向为计算机应用,农业信息化及物联网。