本章主要介绍AuthenticationInfo 和 AuthorizationInfo
一、AuthenticationInfo
AuthenticationInfo有两个作用:
1)如果Realm 是AuthenticatingRealm 子类(包括AuthorizingRealm,它继承AuthenticationRealm),则提供给AuthenticatingRealm 内部使用的CredentialsMatcher进行凭据验证;(如果没有继承它需要在自己的Realm中自己实现验证);
2)提供给SecurityManager来创建Subject(提供身份信息);
MergableAuthenticationInfo 用于提供在多Realm 时合并AuthenticationInfo 的功能,主要合并Principal、如果是其他的如credentialsSalt,会用后边的信息覆盖前边的。
比如HashedCredentialsMatcher , 在验证时会判断AuthenticationInfo 是否是SaltedAuthenticationInfo子类,来获取盐信息。
Account相当于我们之前的User,SimpleAccount是其一个实现;在IniRealm、PropertiesRealm这种静态创建帐号信息的场景中使用,这些Realm 直接继承SimpleAccountRealm,而SimpleAccountRealm 提供了相关的API 来动态维护SimpleAccount;即可以通过这些API来动态增删改查SimpleAccount;动态增删改查角色/权限信息。及如果您的帐号不是特别多,可以使用这种方式。
其他情况一般返回SimpleAuthenticationInfo即可
Shiro SimpleAuthenticationInfo使用
SimpleAuthenticationInfo这里原理很简单,又有一些值得挖掘的东西。 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user,
user.getPassword(),
getName()
);
第一个参数是user,这里好多地方传的时候都是user对象,但是都在备注用户名(可传username)。
第二个参数是user.getPassword(),注意这里是指从数据库中获取的password。
第三个参数是realm,即当前realm的名称。
网上有文章说,这里的user其实是user和username的集合,后端是分两个字段接收的。二、AuthorizationInfo
AuthorizationInfo用于聚合授权信息的:
public interface AuthorizationInfo extends Serializable {
Collection<String> getRoles(); //获取角色字符串信息
Collection<String> getStringPermissions(); //获取权限字符串信息
Collection<Permission> getObjectPermissions(); //获取Permission对象信息
}
当我们使用AuthorizingRealm 时,如果身份验证成功,在进行授权时就通过doGetAuthorizationInfo方法获取角色/权限信息用于授权验证。
Shiro 提供了一个实现SimpleAuthorizationInfo,大多数时候使用这个即可。
对于Account 及SimpleAccount,用于SimpleAccountRealm子类,实现动态角色/权限维护的。
PrincipalCollection
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { ... }
PrincipalCollection是一个身份集合,因为我们可以在Shiro中同时配置多个Realm,所以呢身份信息可能就有多个;因此其提供了PrincipalCollection用于聚合这些身份信息:
public interface PrincipalCollection extends Iterable, Serializable {
Object getPrimaryPrincipal(); //得到主要的身份
<T> T oneByType(Class<T> type); //根据身份类型获取第一个
<T> Collection<T> byType(Class<T> type); //根据身份类型获取一组
List asList(); //转换为List
Set asSet(); //转换为Set
Collection fromRealm(String realmName); //根据Realm名字获取
Set<String> getRealmNames(); //获取所有身份验证通过的Realm名字
boolean isEmpty(); //判断是否为空
}
因为PrincipalCollection聚合了多个,此处最需要注意的是
getPrimaryPrincipal,如果只有一个Principal 那么直接返回即可,如果有多个Principal,则返回第一个(因为内部使用Map存储,所以可以认为是返回任意一个)
;oneByType / byType根据凭据的类型返回相应的Principal;fromRealm 根据Realm 名字(每个Principal 都与一个Realm 关联)获取相应的Principal。