1.认证模块
CAS认证处理器主要由一个认证管理器控制,该管理器负责协调认证处理器的工作。
要了解该模块,必须知道下面几个核心名词(组件):
-
credentials
凭证,证明用户身份的object,比如我们用用户名密码登录的时候,对应一个
UsernamePasswordCredential
,
使用CAS的委托登录时,对应ClientCredential
。 -
principal
主体,及经过认证后,用来保存用户信息的object,见:
org.apereo.cas.authentication.principal.Principal
-
AuthenticationManager
认证管理器,认证的核心
-
AuthenticationHandler
认证处理器,主要功能就是上面提到的凭证认证,还有属性解析
-
PrincipalResolver
主体解析器,用于获取principal。
有的人会有疑问,上面认证结果已经返回了一个
principal
,为啥这里又出现一个解析器呢,
上面的认证处理只是得到一个简单的principal
,我们可能希望从其他地方获取我们想要的属性,比如从别的数据库或服务拿数据,
具体我们下面说
1.1 认证管理器
认证管理器维护了一堆认证处理器,这些处理器是真正实现了认证的核心,
比如使用用户名、密码登录,会有一个处理器来做数据库操作,然后返回一个principal。
它主要包括 凭证认证、主体解析、认证协议检查 三步操作。
-
凭证认证 – 验证凭证,返回一个 principal,你可以配置了多种认证方式,每个认证都会返回一个 principal
-
主体解析 – 见
PrincipalResolver
-
认证协议检查 – 一般不用配置该项,如果你配置了协议检查,管理器会检查你上面的所有认证结果:
- all – 这里并不是说,你配置了多少认证方式,就必须全部认证通过,而是,你有几个credentials,就需要认证成功几次,
即credentials.size == successes.size,比如配置多个认证方式(比如:账号、邮箱、手机号登录),通过邮箱认证成功,
就满足了当前认证; - any – 有任意一个认证成功;该协议有个tryAll参数,目前没搞懂什么作用,暂时设置为false
- uniquePrincipal – 只允许一个principalId存在,意思就是如果当前账号已经在某个地方登陆过了,就不允许再次登陆,
他的做法是,遍历所有的TGT,检查其中的principal.id
,是否与当前的principal.id
系统。 - *notPrevented – 认证过程不出现
PreventedException
,且满足any
认证协议 - *req(required)- 指定的认证处理器如果认证成功,则满足检查
- *groovy – 执行groovy脚本,允许指定多个,see Configuration-Properties.html#groovy-1
- *rest – 通过调用接口进行检查,see Configuration-Properties.html#rest-1
认证协议相关配置:authentication-policy
根据源码[org/apereo/cas/config/CasCoreAuthenticationPolicyConfiguration#authenticationPolicyExecutionPlanConfigurer],
认证协议只能配置一种(所以文档中说的遍历policy纯属胡扯),如果你配置了多种,也是按代码中的优先级,进行配置,优先级:req > all > notPrevented > uniquePrincipal > groovy > rest > any
- all – 这里并不是说,你配置了多少认证方式,就必须全部认证通过,而是,你有几个credentials,就需要认证成功几次,
1.2 认证处理器
上面提到了认证的核心是认证处理器,那么什么是认证处理器?
顾名思义,就是认证的地方,用来处理凭证、解析principal(也可以认为获取用户属性),它的入口需要一个credentials,
最常见的就是 UsernamePasswordCredential
,即用户名密码登录的入参,
出口是一个 principal
,它包含 用户名 和 需要返回的属性(principal_attribute_list)
这个给一个 credentials 与认证处理器的对照表:
credentials | authn handler | 场景 |
---|---|---|
UsernamePasswordCredential | AbstractJdbcUsernamePasswordAuthenticationHandler | 账号密码认证 |
ClientCredential | ClientAuthenticationHandler | 三方认证,如github认证 |
1.3 主体(principal)解析器
principal解析器是用来解析用户信息主体的,
每一个 PrincipalResolver
都会解析出一个principal,最后合并attributes,
常用的PrincipalResolver有:
-
ChainingPrincipalResolver
链式解析,遍历每一个解析器,得到principal列表,最后合并principals:
- principalId – 存在多个 principal 的话,id 取最后一个 principal 的id
- attributes – 合并map,也会涉及到属性重命名
一般只会包含
EchoingPrincipalResolver
,PersonDirectoryPrincipalResolver
两个 -
EchoingPrincipalResolver
如果参数Principal不为空,直接返回,得到的这个principal,也可以看做认证时,就已经拿到的principal
比如你使用用户名密码登录的方式,会配置获取密码的SQL,比如:
select username,password from user where user=?
认证成功后,
username
,password
就会被当做属性,进行collect,然后set到principal -
PersonDirectoryPrincipalResolver
根据
cas.authn.attributeRepository
配置,从数据库中获取属性 -
ProxyingPrincipalResolver
代理解析器,不常用,我们可以通过设置
principalFactory
来自定义解析方法
配置:CasCoreAuthenticationPrincipalConfiguration#personDirectoryPrincipalResolver
2. 总结
结合源码来总结一下认证的流程就是,对于任何给出的凭证,认证管理器都将会做如下操作:
- 遍历所有的认证处理器,进行下面所有步骤:
- 如果处理器支持该凭证(credentials),则尝试认证
- 如果认证成功,尝试解析principal
- 检查认证处理器是否配置了principal解析器
- 如果处理器配置了解析器,尝试用解析器认证credentials
- 如果没有配置解析器,直接返回认证处理器解析的principal
- 检查是否满足安全协议
- 如果满足安全协议,则立即返回
- 如果不满足安全协议,则继续执行
- 如果所有的凭证都不满足安全协议,抛出 AuthenticationException
最后来个流程图,更清晰的了解这个过程(plantuml画流程图好low):