认证初认识
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
根据源码authenticationPolicyExecutionPlanConfigurer,
认证协议只能配置一种(所以文档中说的遍历policy纯属胡扯),如果你配置了多种,也是按代码中的优先级,进行配置,优先级:
req > all > notPrevented > uniquePrincipal > groovy > rest > any
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
最后来个流程图,更清晰的了解这个过程: