点融网开源权限控制框架Uniauth简介

Uniauth是一个基于CAS和Spring Security开源产品而开发的权限控制框架,它的目标是服务于点融网内部的各个子系统,只要集成了该框架,就能以很小的代价实现认证和授权功能。而权限设计是开发系统中不可规避的一个环节。

为什么要做权限控制框架

每个公司内部都有大量的子系统,点融网也不例外。

这些子系统有为普通员工服务的,比如各种OA系统;有为专门业务操作人员服务的,比如电销系统,库存管理系统;也有为技术人员服务的,比如我们常见的git,confluence,jira等系统。

很多时候,这些子系统都有各自独立的账户体系和权限控制方式。当有新员工入职时,需要在各个必须的子系统中为其开设帐号并受以权限,浪费了大量的人力物力。而且,各个子系统权限控制的模式参差不齐,权限控制的数据模型也不尽相同,很多时候都留有安全隐患。比如,使用Fiddler等工具拦截http报文后,修改一些参数便可以访问到本不该被访问到的隐私内容。

另外,作为使用这些子系统的员工也比较痛苦,因为他们有可能在这些子系统中设置不同的密码,密码记忆混乱甚至忘记密码也常有发生。

如果这些子系统可以集成一套成熟的权限控制框架,使用唯一的一套账户体系,能够完成统一登录和登出(Single Sign On/Off),甚至各个子系统的管理员可以自行分配属于自己系统的组、角色、权限等信息,将会是一件大快人心的事!

综上所述,您可能认为我们确实应该设计一套权限控制的框架来帮我们来做这件事。在设计这套框架之前,让我们来看看需要做权限控制的一些常见业务场景。

需要权限控制的常见业务场景

页面级别(视图层)

控制菜单展现,按钮显示,数据渲染

方法访问控制

方法和类,事前和事后,aop切点语法支持

数据过滤

同样一份数据,对不同的人而言看到的数量或属性不同

请求的URL的拦截

只有属于某些/个角色的登录用户才可以访问某些模式的URL

某些方法调用需要将入参和当前用户相关联的情况

比如对于密码修改方法,登录人员的只能修改自己账户的密码

更细粒度的控制

使用ACL对域对象制定更细粒度的权限访问策略

其他更多种的访问控制策略的引入

比如基于IP(支持CIDR表示),基于访问时间段,remember me功能等等

可以看到,做到尽善尽美的权限控制十分不易,如果自己去实现所有这些业务场景的控制将花费大量力气,而且也不一定能做好。

那究竟该如何这个设计权限控制框架,或者说它的设计原则又是什么呢?

Uniauth的设计原则

我们认为,Uniauth的设计原则应该体现在以下方面:

兼容目前子系统的权限控制模型

子系统的权限模型可以适配转换进入新系统的权限模型。

具有广泛的第三方鉴权系统或协议的可接纳性

需要广泛的鉴权系统/协议的集成支持,包括但不限于:sso,oauth,ntlm/kerberos,openid,ldap/ms active directory,saml...因为说不清未来要集成什么东西。但有需要时可以通过配置,或以较小的代价接入。

具有良好扩展性

扩展性表现在认证和授权的各个阶段和环节,每个环节都有默认实现,但可以提供途径根据需要进行覆写和干预。这通常发生在子系统认为框架提供的某个环节不爽的场景,比如我觉得公共登录页很丑,我要定制自己的登录页。

方便的组,角色,人员权限分配和控制

当新加入业务操作人员时,管理人员只需要简短操作就可以方便的进行账户权限分配,控制,管理,权限开关设置等,

代码侵入性

权限控制对系统业务级代码无侵入性,或有较少侵入性。

使用成熟解决方案,不重复造轮子

使用业界久经考验的成熟开源方案,少些代码,遇到问题通过社区很快得到解决。

基于以上设计原则,我们选择了CAS + Spring Security的开源组合来作为我们Uniauth框架开发的基础。

Uniauth简介

Uniauth是一个基于CAS和Spring Security开源产品而开发的权限控制框架,其中统一认证功能由CAS提供,当访问多个集成了Uniauth框架的业务子系统时,只要用户登录一次,便可以访问所有其他业务子系统(SSO功能);授权功能由Spring Security提供,所有Spring Security的功能都可以使用。

同时我们对Spring Security的某些常用关键功能进行了封装和再增强,以便使您更专注于权限控制的业务实现(比如通过注解,表达式或JSP Security Tag)而无需了解Spring Security的底层配置和机制。所以,Uniauth框架基于Spring Security,而又不仅仅是一个Spring Security。

事实上,我们提供的是一个定制版的Spring Security框架,更好用,更强大,这主要体现在以下几点:

1、无缝集成CAS实现SSO

在集成Uniauth框架后,用户访问本业务系统,一旦检测到用户未登陆,会被自动引导到CAS统一登录页,完成登录后再跳转到业务系统,业务系统可以自动获取该用户的基本属性,如用户名,域信息,角色信息等(还可对属性进行扩展,见下文)。同时,无需再登陆即可访问其他集成的业务子系统。

2、对XML和数据库两方定义的URL拦截数据进行合并

在普通情况下使用Spring Security,对URL拦截的定义位于其配置文件的标签下的中,如:

如果进行定制的话,常规做法是实现FilterInvocationSecurityMetadataSource接口,用于加载预定义在数据库中的intercept-url定义,以便用于运行时权限判断。

但上面两种情况通常是互斥的,这是因为配置文件中的定义由Spring Security框架在启动时加载,并且注入到一个FilterSecurityInterceptor实例中;来自数据库定义的MetadataSource会被注入到另外的一个自定义FilterSecurityInterceptor实例中。在运行时权限判断中,两个FilterSecurityInterceptor无论谁先执行谁后执行,都会在基于Role的判断中影响或覆盖另外一个。

在Uniauth中会自动对这两边定义的intercept-url进行合并,并注入到同一个FilterSecurityInterceptor实例中,所有intercept-url定义都会起作用。

3、在URL定义中寻找最优匹配请求路径的条目

在权限控制的开始阶段,我们通常会做出粗糙控制,比如规定只有登陆用户才能访问本业务系统:

随着业务的不断精细化,我们可能会定义各种不同匹配模式(基于ant或正则),如只有ROLE_ADMIN角色才能访问/admin开始的url:

在普通的Spring Security使用中,这两个定义的先后顺序很重要,因为它会自上而下进行扫描,一旦发现有一条路径匹配就会选用。

这样就会产生问题,比如一个普通用户(ROLE_USER),访问了/admin/update/info这个url,因为第一条定义表明只要是认证过的用户就可以访问所有形式的url,这样就造成了普通用户也可以访问管理员才可以访问的页面。

在Uniauth中不会产生这个问题,Uniauth会把来自配置文件或数据库中的所有匹配请求路径的url定义聚集起来,然后从中选择一个最匹配(最长匹配)的进行选用,无论url定义的顺序是什么。

对应于上面的例子,/admin/update/info这个请求路径对于两个url定义都匹配,但是显然更匹配第二个,所以会选用第二个定义。但第二个要求是ROLE_ADMIN角色才能访问,用户本身是ROLE_USER,所以会拒绝他的请求。

我们建议对所有需要保护的资源url进行定义切分,因为不被保护的url资源属于公用资源,谁都可以访问。

4、添加hasPermission表达式支持

我们在Uniauth中添加了对hasPermission表达式的支持,hasPermission表达式是最精细的,最彻底的权限控制方式,用于判断当前登陆用户对于某个业务对象是否有某种访问权限。

在Uniauth中,您只要实现UniauthPermissionEvaluator接口,或者从UniauthPermissionEvaluatorImpl扩展,根据自己的需要覆写两个hasPermission方法或其中一个即可,hasPermission表达式可以内嵌在@PreAuthorize注解中,或者也可以使用在JSP安全标签中。

5、对用户登录session进行并发控制

为了安全考虑,我们配置了并发Session访问控制,即Concurrent Session Control。当同一个账户在不同的Session会话中访问同一个业务系统时,第二个Session会将第一个Session会话踢出,如果用户在第一个Session会话中继续活动,会被提示“对不起,您的会话超时,或者您的账号在另外一个窗口中已登录,导致本次会话结束,如有需要,请重新登录!”,引导用户登陆或彻底退出登录系统。

6、对UserDetails对象随需进行扩展

UserDetails在Spring Security中是一个很重要的对象,它代表了通过认证后的用户实体,即principal对象。

我们通常使用principal对象在@PreAuthorize中结合SpEL(Spring Expression Language)进行基本的权限控制,看看当前用户实体是否有权限进行某个方法的调用,这是权限控制中很重要的一个环节。比如对如下方法控制:

@PreAuthorize("hasRole('ROLE_SUPER_ADMIN') and principal.permMap['DOMAIN'] != null and principal.permMap['DOMAIN'].contains('techops')")

public Response resetPassword(@RequestBody UserParam userParam) { ... }

从UserDetails中可以获取到跟当前登录用户相关联的属性,比如用户名,密码,账户是否被锁定,密码是否过期,用户被授予的角色列表等基本信息。

在Uniauth框架中对UserDetails进行了基本扩充,除包含上述用户信息外,我们还添加了当前用户登录的域信息,用户在该域上的权限(privilege)信息等。

另外,每个子系统可能有不同业务需要,我们添加了UserInfoCallBack回调接口,只要业务系统实现了它,就能在UserDetails中添加自己需要的扩展用户属性,比如该用户所有的组列表信息,或者跟自己业务系统相关的其他用户属性信息等。

在大部分情况下,添加扩展属性的目的是用于上面介绍的@PreAuthorize表达式判断,或者用于自身业务操作的其他目的。

Uniauth框架和子系统的集成框架图

Uniauth系统已经上线,欢迎有集成需求的系统跟我们联系,我们将竭诚提供集成支撑服务。

本文作者:许增伟(David Xu),现任点融网成都团队架构组开发工程师,主要开发与业务无关的横切系统和组件,如权限控制系统,消息组件,日志组件和一些公共管理工具等等。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,078评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,947评论 4 60
  • 【约拿书2: 9】但我必用感谢的声音献祭与你。我所许的愿, 我必偿还。救恩出于耶和华。 亲爱的弟兄姐妹们,我们每天...
    高桥先生阅读 370评论 0 0
  • 借考察调研的时机,再次来到了美丽的杭州,因平时有跑步的习惯,跑西湖的冲动立马涌上心头…… 肇庆...
    高洪昭阅读 472评论 0 0