相关阅读
- Spring Shiro流程简析 登录请求处理
- Spring Shiro基础组件 AuthenticationInfo
- Spring Shiro基础组件 AuthorizationInfo
- Spring Shiro基础组件 Permission
- Spring Shiro基础组件 Subject
简介
定义了访问安全实体,比如:用户、角色、权限的接口,以支持鉴权和授权操作;
核心方法
/**
* 返回名称
* 应用程序内唯一
*/
String getName();
/**
* 是否支持指定AuthenticationToken
*/
boolean supports(AuthenticationToken token);
/**
* 鉴权
*/
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
实现子类
public interface Realm
public abstract class CachingRealm implements Realm, Nameable, CacheManagerAware, LogoutAware // 实现getName()接口,提供缓存算法模板,由子类实现算法细节和选择是否开启缓存功能
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable // 实现supports(AuthenticationToken)接口/缓存算法细节/getAuthenticationInfo(AuthenticationToken)算法模板/init()算法模板,提供抽象方法doGetAuthenticationInfo(AuthenticationToken)onInit()方法默认实现,由子类实现算法细节
public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware // 实现obInit()算法细节/getAuthorizationInfo(PrincipalCollection)算法模板,提供抽象方法doGetAuthorizationInfo(PrincipalCollection)由子类实现算法细节
public class SimpleAccountRealm extends AuthorizingRealm // 实现doGetAuthenticationInfo(AuthenticationToken)/doGetAuthorizationInfo(PrincipalCollection)算法细节
CachingRealm
简介
扩展Realm
接口的基础抽象类,提供缓存支持;
同时提供getAvailablePrincipal(PrincipalCollection)
方法获取领域特定的主体/身份信息;
核心方法
// 名称,默认className_id(递增的原子Integer)
private String name;
// 开启缓存标识,默认true
private boolean cachingEnabled;
// 缓存管理器
private CacheManager cacheManager;
/**
* 模板方法
*/
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
afterCacheManagerSet();
}
/**
* 模版子方法,由子类实现覆写添加额外的处理逻辑
*/
protected void afterCacheManagerSet() {
}
/**
* 登出时清除缓存
*/
public void onLogout(PrincipalCollection principals) {
clearCache(principals);
}
/**
* 清除缓存
*/
protected void clearCache(PrincipalCollection principals) {
// 主体集合不为空
if (!isEmpty(principals)) {
doClearCache(principals);
log.trace("Cleared cache entries for account with principals [{}]", principals);
}
}
/**
* 清除缓存模板方法
* 具体动作由子类实现
*/
protected void doClearCache(PrincipalCollection principals) {
}
/**
* 获取可用principal
*/
protected Object getAvailablePrincipal(PrincipalCollection principals) {
Object primary = null;
if (!isEmpty(principals)) {
// 尝试获取此特定领域的“主要”主体
Collection thisPrincipals = principals.fromRealm(getName());
if (!CollectionUtils.isEmpty(thisPrincipals)) {
primary = thisPrincipals.iterator().next();
} else {
// 获取全局的“主要”主体
//no principals attributed to this particular realm. Fall back to the 'master' primary:
primary = principals.getPrimaryPrincipal();
}
}
return primary;
}
AuthenticatingRealm
简介
Realm
的顶级抽象实现,仅实现身份验证(登录),授权(访问控制)由子类实现;
默认情况下禁止身份验证缓存,保证和Shiro1.1及更早版本的向后兼容性;
当领域满足以下任一条件才能启动身份验证缓存:
doGetAuthenticationInfo
实现返回的AuthenticationInfo
实例,其中credentials
被加密;doGetAuthenticationInfo
实现返回的AuthenticationInfo
实例,其中credentials
未加密,但存储AuthenticationInfo
实例的缓存区域不会溢出到磁盘,并且不会通过不安全的网络传输缓存条目;
如果启用身份验证缓存,此抽象类实现会将子类实现返回的AuthenticationInfo
实例直接放入缓存中;
核心方法
// 判断给定的credentials是否匹配已存储的值
private Credentialsmatcher credentialsMatcher;
// 身份验证缓存
private Cache<Object, AuthenticationInfo> authenticationCache;
// 身份验证缓存开启标识
private boolean authenticationCachingEnable;
// 身份验证缓存名称
private String authenticationCacheName;
// 此领域支持的身份验证令牌的类型,Realm.supports(AuthenticationToken)默认实现使用其判断给定的身份验证令牌类型是否支持
private Class<? extends AuthenticationToken> authenticationTokenClass;
/**
* 构造方法
*/
public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
// 默认为UsernamePasswordToken
authenticationTokenClass = UsernamePasswordToken.class;
// 默认不开启缓存,保证早期版本向后兼容性
//retain backwards compatibility for Shiro 1.1 and earlier. Setting to true by default will probably cause
//unexpected results for existing applications:
this.authenticationCachingEnabled = false;
// 实例数原子加一
int instanceNumber = INSTANCE_COUNT.getAndIncrement();
this.authenticationCacheName = getClass().getName() + DEFAULT_AUTHENTICATION_CACHE_SUFFIX;
if (instanceNumber > 0) {
this.authenticationCacheName = this.authenticationCacheName + "." + instanceNumber;
}
if (cacheManager != null) {
setCacheManager(cacheManager);
}
if (matcher != null) {
setCredentialsMatcher(matcher);
}
}
/**
* 是否开启身份验证缓存
*/
public boolean isAuthenticationCachingEnabled() {
return this.authenticationCachingEnabled && isCachingEnabled();
}
/**
* 设置身份验证缓存开启标识
*/
public void setAuthenticationCachingEnabled(boolean authenticationCachingEnabled) {
this.authenticationCachingEnabled = authenticationCachingEnabled;
if (authenticationCachingEnabled) {
// 开启缓存则需要更新父类开启缓存标识
setCachingEnabled(true);
}
}
/**
* 设置身份验证缓存名称
*/
public void setName(String name) {
super.setName(name);
String authcCacheName = this.authenticationCacheName;
if (authcCacheName != null && authcCacheName.startsWith(getClass().getName())) {
// 如果缓存名称存在且为默认格式,则更新为当前设置的名称
//get rid of the default heuristically-created cache name. Create a more meaningful one
//based on the application-unique Realm name:
this.authenticationCacheName = name + DEFAULT_AUTHENTICATION_CACHE_SUFFIX;
}
}
/**
* Realm.supports的默认实现
* getAuthenticationTokenClass()默认为UsernamePasswordToken
* 子类修改默认实现只需要通过setAuthenticationTokenClass修改authenticationTokenClass即可
*/
public boolean supports(AuthenticationToken token) {
return token != null && getAuthenticationTokenClass().isAssignableFrom(token.getClass());
}
/**
* 模板方法,初始化
* 如果cache/cacheManager存在,则先从缓存中查找,否则每次都会由子类实现从底层数据存储中查找
*/
public final void init() {
//trigger obtaining the authorization cache if possible
getAvailableAuthenticationCache();
onInit();
}
/**
* 获取可用的身份验证缓存
*/
private Cache<Object, AuthenticationInfo> getAvailableAuthenticationCache() {
Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
boolean authcCachingEnabled = isAuthenticationCachingEnabled();
if (cache == null && authcCachingEnabled) {
// 如果cache不存在且开启身份验证缓存,则从cacheManager中获取缓存
cache = getAuthenticationCacheLazy();
}
return cache;
}
/**
* 从可用的缓存管理器中获取身份验证缓存
*/
private Cache<Object, AuthenticationInfo> getAuthenticationCacheLazy() {
// 校验身份验证缓存是否为空
if (this.authenticationCache == null) {
log.trace("No authenticationCache instance set. Checking for a cacheManager...");
CacheManager cacheManager = getCacheManager();
// 如果缓存管理器可用
if (cacheManager != null) {
String cacheName = getAuthenticationCacheName();
log.debug("CacheManager [{}] configured. Building authentication cache '{}'", cacheManager, cacheName);
// 根据缓存名称查找缓存
this.authenticationCache = cacheManager.getCache(cacheName);
}
}
return this.authenticationCache;
}
/**
* 模板子方法,由子类覆写添加额外的处理逻辑
*/
protected void onInit() {
}
/**
* 根据token从缓存中查找身份验证信息
*/
private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token) {
AuthenticationInfo info = null;
Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();
if (cache != null && token != null) {
log.trace("Attempting to retrieve the AuthenticationInfo from cache.");
Object key = getAuthenticationCacheKey(token);
info = cache.get(key);
if (info == null) {
log.trace("No AuthorizationInfo found in cache for key [{}]", key);
} else {
log.trace("Found cached AuthorizationInfo for key [{}]", key);
}
}
return info;
}
/**
* 缓存身份验证信息
*/
private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) {
if (!isAuthenticationCachingEnabled(token, info)) {
log.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token);
//return quietly, caching is disabled for this token/info pair:
return;
}
Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();
if (cache != null) {
Object key = getAuthenticationCacheKey(token);
cache.put(key, info);
log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info);
}
}
/**
* 模板方法,获取身份验证信息
* 先从缓存中获取
* 缓存获取失败,则由子类实现从底层数据存储中获取
* 获取到后再次校验token和info是否匹配
*/
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 先从缓存中查找
AuthenticationInfo info = getCachedAuthenticationInfo(token);
if (info == null) {
// 由子类实现从底层数据存储中查找
//otherwise not cached, perform the lookup:
info = doGetAuthenticationInfo(token);
log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
if (token != null && info != null) {
// 将结果缓存
cacheAuthenticationInfoIfPossible(token, info);
}
} else {
log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
}
if (info != null) {
// 校验token和info是否匹配
assertCredentialsMatch(token, info);
} else {
log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);
}
return info;
}
/**
* 模板子方法,由子类实现从底层数据存储中查找身份验证信息
*/
protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
/**
* 校验token是否匹配info
*/
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
"credentials during authentication. If you do not wish for credentials to be examined, you " +
"can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
/**
* 根据token获取缓存中身份验证信息对应的键
* 存储缓存时使用的键
* 默认使用token.getPrincipal(一般是用户名)
*/
protected Object getAuthenticationCacheKey(AuthenticationToken token) {
return token != null ? token.getPrincipal() : null;
}
/**
* 根据principalCollection获取缓存中身份验证信息对应的键
* 清除缓存时使用的健
* 如果登出时删除账户缓存的身份验证信息,需要保证该方法返回值和getAuthenticationInfoCacheKey(AuthenticationToken)一致
*/
protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
return getAvailablePrincipal(principals);
}
/**
* 清除缓存
*/
@Override
protected void doClearCache(PrincipalCollection principals) {
// 调用父类方法进行清除
super.doClearCache(principals);
// 清除缓存的身份验证信息
clearCachedAuthenticationInfo(principals);
}
/**
* 清除缓存的身份验证信息
*/
protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
if (!isEmpty(principals)) {
Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();
//cache instance will be non-null if caching is enabled:
if (cache != null) {
// 根据principals生成缓存的KEY
Object key = getAuthenticationCacheKey(principals);
cache.remove(key);
}
}
}
AuthorizingRealm
简介
在AuthenticatingRealms
的基础上增加授权(访问控制)支持;
核心方法
// 授权缓存开启标识
private boolean authorizationCachingEnabled;
// 授权缓存
private Cache<Object, AuthorizationInfo> authorizationCache;
// 授权缓存名称
private String authorizationCacheName;
// 权限解析器
private PermissionResolver permissionResolver;
// 权限角色解析器
private RolePermissionResolver permissionRoleResolver;
/**
* 构造方法
*/
public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
super();
if (cacheManager != null) setCacheManager(cacheManager);
if (matcher != null) setCredentialsMatcher(matcher);
// 默认开启授权缓存
this.authorizationCachingEnabled = true;
// 默认权限解析器为WildcardPermissionResolver
this.permissionResolver = new WildcardPermissionResolver();
int instanceNumber = INSTANCE_COUNT.getAndIncrement();
// 默认的授权缓存名称
this.authorizationCacheName = getClass().getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;
if (instanceNumber > 0) {
this.authorizationCacheName = this.authorizationCacheName + "." + instanceNumber;
}
}
/**
* 设置缓存名称
*/
public void setName(String name) {
// 设置父类缓存名称
super.setName(name);
String authzCacheName = this.authorizationCacheName;
if (authzCacheName != null && authzCacheName.startsWith(getClass().getName())) {
//get rid of the default class-name based cache name. Create a more meaningful one
//based on the application-unique Realm name:
this.authorizationCacheName = name + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;
}
}
/**
* 授权
* 算法模板
*/
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
return null;
}
AuthorizationInfo info = null;
if (log.isTraceEnabled()) {
log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
}
// 先从授权缓存中获取
Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
if (cache != null) {
if (log.isTraceEnabled()) {
log.trace("Attempting to retrieve the AuthorizationInfo from cache.");
}
// 获取缓存KEY
Object key = getAuthorizationCacheKey(principals);
info = cache.get(key);
if (log.isTraceEnabled()) {
if (info == null) {
log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
} else {
log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");
}
}
}
// 缓存中未找到
if (info == null) {
// 由子类实现从底层数据存储中查找
// Call template method if the info was not found in a cache
info = doGetAuthorizationInfo(principals);
// If the info is not null and the cache has been created, then cache the authorization info.
if (info != null && cache != null) {
// 缓存授权信息
// 思考,如果这时候authorizationCachingEnabled为false,是不是不应该缓存?
// 建议和AuthenticatingRealm.cacheAuthenticationInfoIfPossible实现一致
if (log.isTraceEnabled()) {
log.trace("Caching authorization info for principals: [" + principals + "].");
}
Object key = getAuthorizationCacheKey(principals);
cache.put(key, info);
}
}
return info;
}
/**
* 根据PrincipalCollection生成缓存KEY
*/
protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
return principals;
}
/**
* 授权时处理
* 算法细节,由子类实现从底层数据存储中查找授权信息
*/
protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);
/**
* 清除PrincipalCollection关联的缓存
*/
@Override
protected void doClearCache(PrincipalCollection principals) {
// 调用父类方法清除关联缓存
super.doClearCache(principals);
// 清除授权缓存
clearCachedAuthorizationInfo(principals);
}
/**
* 清除PrincipalCollection关联的授权缓存
*/
protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
return;
}
Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
//cache instance will be non-null if caching is enabled:
if (cache != null) {
// 清除授权缓存
Object key = getAuthorizationCacheKey(principals);
cache.remove(key);
}
}
/**
* 获取授权信息中的权限列表
*/
protected Collection<Permission> getPermissions(AuthorizationInfo info) {
Set<Permission> permissions = new HashSet<Permission>();
if (info != null) {
// 获取类型安全的权限
Collection<Permission> perms = info.getObjectPermissions();
if (!CollectionUtils.isEmpty(perms)) {
permissions.addAll(perms);
}
// 获取基于字符串的权限
perms = resolvePermissions(info.getStringPermissions());
if (!CollectionUtils.isEmpty(perms)) {
permissions.addAll(perms);
}
// 获取基于角色的权限
perms = resolveRolePermissions(info.getRoles());
if (!CollectionUtils.isEmpty(perms)) {
permissions.addAll(perms);
}
}
if (permissions.isEmpty()) {
return Collections.emptySet();
} else {
return Collections.unmodifiableSet(permissions);
}
}
/**
* 解析基于字符串的权限
*/
private Collection<Permission> resolvePermissions(Collection<String> stringPerms) {
Collection<Permission> perms = Collections.emptySet();
PermissionResolver resolver = getPermissionResolver();
if (resolver != null && !CollectionUtils.isEmpty(stringPerms)) {
perms = new LinkedHashSet<Permission>(stringPerms.size());
for (String strPermission : stringPerms) {
if (StringUtils.clean(strPermission) != null) {
// 解析权限
Permission permission = resolver.resolvePermission(strPermission);
perms.add(permission);
}
}
}
return perms;
}
/**
* 解析基于角色的权限
*/
private Collection<Permission> resolveRolePermissions(Collection<String> roleNames) {
Collection<Permission> perms = Collections.emptySet();
RolePermissionResolver resolver = getRolePermissionResolver();
if (resolver != null && !CollectionUtils.isEmpty(roleNames)) {
perms = new LinkedHashSet<Permission>(roleNames.size());
for (String roleName : roleNames) {
// 解析权限
Collection<Permission> resolved = resolver.resolvePermissionsInRole(roleName);
if (!CollectionUtils.isEmpty(resolved)) {
perms.addAll(resolved);
}
}
}
return perms;
}
/**
* 判断PrincipalCollection关联的授权信息是否包含指定字符串权限
*/
public boolean isPermitted(PrincipalCollection principals, String permission) {
// 解析基于字符串的权限
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p);
}
/**
* 判断PrincipalCollection关联的授权信息是否包含指定权限
*/
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
/**
* 判断授权信息是否包含指定权限
*/
//visibility changed from private to protected per SHIRO-332
protected boolean isPermitted(Permission permission, AuthorizationInfo info) {
// 获取授权信息的所有权限
Collection<Permission> perms = getPermissions(info);
if (perms != null && !perms.isEmpty()) {
// 遍历权限集合
for (Permission perm : perms) {
if (perm.implies(permission)) {
return true;
}
}
}
return false;
}
/**
* 批量判断授权信息是否包含指定字符串权限列表
*/
public boolean[] isPermitted(PrincipalCollection subjectIdentifier, String... permissions) {
List<Permission> perms = new ArrayList<Permission>(permissions.length);
for (String permString : permissions) {
// 解析基于字符串的权限
perms.add(getPermissionResolver().resolvePermission(permString));
}
return isPermitted(subjectIdentifier, perms);
}
public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) {
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permissions, info);
}
/**
* 批量判断授权信息是否包含指定权限集合
*/
protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {
boolean[] result;
if (permissions != null && !permissions.isEmpty()) {
int size = permissions.size();
result = new boolean[size];
int i = 0;
// 遍历指定权限列表
for (Permission p : permissions) {
result[i++] = isPermitted(p, info);
}
} else {
result = new boolean[0];
}
return result;
}
/**
* 判断PrincipalCollection关联的授权信息是否包含指定字符串权限列表
*/
public boolean isPermittedAll(PrincipalCollection subjectIdentifier, String... permissions) {
if (permissions != null && permissions.length > 0) {
Collection<Permission> perms = new ArrayList<Permission>(permissions.length);
for (String permString : permissions) {
// 解析基于字符串的权限
perms.add(getPermissionResolver().resolvePermission(permString));
}
return isPermittedAll(subjectIdentifier, perms);
}
return false;
}
/**
* 判断PrincipalCollection关联的授权信息是否包含指定权限集合
*/
public boolean isPermittedAll(PrincipalCollection principal, Collection<Permission> permissions) {
AuthorizationInfo info = getAuthorizationInfo(principal);
return info != null && isPermittedAll(permissions, info);
}
/**
* 判断授权信息是否包含指定权限集合
*/
protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
if (permissions != null && !permissions.isEmpty()) {
for (Permission p : permissions) {
if (!isPermitted(p, info)) {
return false;
}
}
}
return true;
}
/**
* 校验PrincipalCollection关联的授权信息是否包含指定字符串权限
*/
public void checkPermission(PrincipalCollection subjectIdentifier, String permission) throws AuthorizationException {
// 解析基于字符串的权限
Permission p = getPermissionResolver().resolvePermission(permission);
checkPermission(subjectIdentifier, p);
}
/**
* 校验PrincipalCollection关联的授权信息是否包含指定权限
*/
public void checkPermission(PrincipalCollection principal, Permission permission) throws AuthorizationException {
AuthorizationInfo info = getAuthorizationInfo(principal);
checkPermission(permission, info);
}
/**
* 校验授权信息是否包含指定权限
*/
protected void checkPermission(Permission permission, AuthorizationInfo info) {
if (!isPermitted(permission, info)) {
String msg = "User is not permitted [" + permission + "]";
throw new UnauthorizedException(msg);
}
}
/**
* 校验PrincipalCollection关联的授权信息是否包含指定字符串权限列表
*/
public void checkPermissions(PrincipalCollection subjectIdentifier, String... permissions) throws AuthorizationException {
if (permissions != null) {
for (String permString : permissions) {
checkPermission(subjectIdentifier, permString);
}
}
}
/**
* 校验PrincipalCollection关联的授权信息是否包含指定权限集合
*/
public void checkPermissions(PrincipalCollection principal, Collection<Permission> permissions) throws AuthorizationException {
// 获取身份验证信息
AuthorizationInfo info = getAuthorizationInfo(principal);
checkPermissions(permissions, info);
}
/**
* 校验授权信息是否包含指定权限集合
*/
protected void checkPermissions(Collection<Permission> permissions, AuthorizationInfo info) {
if (permissions != null && !permissions.isEmpty()) {
for (Permission p : permissions) {
checkPermission(p, info);
}
}
}
/**
* 判断PrincipalCollection关联的授权信息是否包含指定角色
*/
public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
AuthorizationInfo info = getAuthorizationInfo(principal);
return hasRole(roleIdentifier, info);
}
/**
* 判断授权信息是否包含指定角色
*/
protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
}
/**
* 批量判断PrincipalCollection关联的授权信息是否包含指定角色集合
*/
public boolean[] hasRoles(PrincipalCollection principal, List<String> roleIdentifiers) {
AuthorizationInfo info = getAuthorizationInfo(principal);
boolean[] result = new boolean[roleIdentifiers != null ? roleIdentifiers.size() : 0];
if (info != null) {
result = hasRoles(roleIdentifiers, info);
}
return result;
}
/**
* 批量判断授权信息是否包含指定角色集合
*/
protected boolean[] hasRoles(List<String> roleIdentifiers, AuthorizationInfo info) {
boolean[] result;
if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) {
int size = roleIdentifiers.size();
result = new boolean[size];
int i = 0;
for (String roleName : roleIdentifiers) {
result[i++] = hasRole(roleName, info);
}
} else {
result = new boolean[0];
}
return result;
}
/**
* 判断PrincipalCollection关联的授权信息是否包含指定角色集合
*/
public boolean hasAllRoles(PrincipalCollection principal, Collection<String> roleIdentifiers) {
AuthorizationInfo info = getAuthorizationInfo(principal);
return info != null && hasAllRoles(roleIdentifiers, info);
}
/**
* 判断授权信息是否包含指定角色集合
*/
private boolean hasAllRoles(Collection<String> roleIdentifiers, AuthorizationInfo info) {
if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) {
for (String roleName : roleIdentifiers) {
if (!hasRole(roleName, info)) {
return false;
}
}
}
return true;
}
/**
* 校验PrincipalCollection关联的授权信息是否包含指定角色
*/
public void checkRole(PrincipalCollection principal, String role) throws AuthorizationException {
AuthorizationInfo info = getAuthorizationInfo(principal);
checkRole(role, info);
}
/**
* 校验授权信息是否包含指定角色
*/
protected void checkRole(String role, AuthorizationInfo info) {
if (!hasRole(role, info)) {
String msg = "User does not have role [" + role + "]";
throw new UnauthorizedException(msg);
}
}
/**
* 校验PrincipalCollection关联的授权信息是否包含指定角色集合
*/
public void checkRoles(PrincipalCollection principal, Collection<String> roles) throws AuthorizationException {
AuthorizationInfo info = getAuthorizationInfo(principal);
checkRoles(roles, info);
}
/**
* 校验授权信息是否包含指定角色列表
*/
public void checkRoles(PrincipalCollection principal, String... roles) throws AuthorizationException {
checkRoles(principal, Arrays.asList(roles));
}
/**
* 校验授权信息是否包含指定角色集合
*/
protected void checkRoles(Collection<String> roles, AuthorizationInfo info) {
if (roles != null && !roles.isEmpty()) {
for (String roleName : roles) {
checkRole(roleName, info);
}
}
}
SimpleAccountRealm
简介
SimpleAccountRealm
是AuthorizingRealm
的简单实现,使用配置的用户账户集合和角色集合来支持身份验证和授权;
每个用户账户指定用户名、密码、角色;角色映射权限,并和用户关联;
用户账户和角色存储在内存的Map
中,所以两者总数不能太大;
核心方法
// 存储用户账户
protected final Map<String, SimpleAccount> users; //username-to-SimpleAccount
// 存储角色
protected final Map<String, SimpleRole> roles; //roleName-to-SimpleRole
// 用户账户的读写锁
protected final ReadWriteLock USERS_LOCK;
// 角色的读写锁
protected final ReadWriteLock ROLES_LOCK;
/**
* 构造方法
*/
public SimpleAccountRealm() {
this.users = new LinkedHashMap<String, SimpleAccount>();
this.roles = new LinkedHashMap<String, SimpleRole>();
USERS_LOCK = new ReentrantReadWriteLock();
ROLES_LOCK = new ReentrantReadWriteLock();
// 基于内存实现底层数据存储,无需缓存
//SimpleAccountRealms are memory-only realms - no need for an additional cache mechanism since we're
//already as memory-efficient as we can be:
setCachingEnabled(false);
}
/**
* 根据用户名查找用户
*/
protected SimpleAccount getUser(String username) {
USERS_LOCK.readLock().lock();
try {
return this.users.get(username);
} finally {
USERS_LOCK.readLock().unlock();
}
}
/**
* 判断指定用户名是否存在
*/
public boolean accountExists(String username) {
return getUser(username) != null;
}
/**
* 增加用户
*/
public void addAccount(String username, String password) {
addAccount(username, password, (String[]) null);
}
/**
* 增加用户
*/
public void addAccount(String username, String password, String... roles) {
Set<String> roleNames = CollectionUtils.asSet(roles);
SimpleAccount account = new SimpleAccount(username, password, getName(), roleNames, null);
add(account);
}
/**
* 获取账户的用户名
*/
protected String getUsername(SimpleAccount account) {
return getUsername(account.getPrincipals());
}
/**
* 获取账户的用户名
*/
protected String getUsername(PrincipalCollection principals) {
return getAvailablePrincipal(principals).toString();
}
/**
* 增加用户
*/
protected void add(SimpleAccount account) {
// 获取用户名
String username = getUsername(account);
USERS_LOCK.writeLock().lock();
try {
this.users.put(username, account);
} finally {
USERS_LOCK.writeLock().unlock();
}
}
/**
* 根据角色名称查找角色
*/
protected SimpleRole getRole(String rolename) {
ROLES_LOCK.readLock().lock();
try {
return roles.get(rolename);
} finally {
ROLES_LOCK.readLock().unlock();
}
}
/**
* 判断指定角色名是否存在
*/
public boolean roleExists(String name) {
return getRole(name) != null;
}
/**
* 增加角色
*/
public void addRole(String name) {
add(new SimpleRole(name));
}
/**
* 增加角色
*/
protected void add(SimpleRole role) {
ROLES_LOCK.writeLock().lock();
try {
roles.put(role.getName(), role);
} finally {
ROLES_LOCK.writeLock().unlock();
}
}
/**
* 字符串切分成Set
*/
protected static Set<String> toSet(String delimited, String delimiter) {
if (delimited == null || delimited.trim().equals("")) {
return null;
}
Set<String> values = new HashSet<String>();
String[] rolenamesArray = delimited.split(delimiter);
for (String s : rolenamesArray) {
String trimmed = s.trim();
if (trimmed.length() > 0) {
values.add(trimmed);
}
}
return values;
}
/**
* 鉴权时处理
* 算法细节,根据token从内存MAP中获取鉴权信息
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
SimpleAccount account = getUser(upToken.getUsername());
if (account != null) {
if (account.isLocked()) {
throw new LockedAccountException("Account [" + account + "] is locked.");
}
if (account.isCredentialsExpired()) {
String msg = "The credentials for account [" + account + "] are expired";
throw new ExpiredCredentialsException(msg);
}
}
return account;
}
/**
* 授权时处理
* 算法细节,根据PrincipalCollection从内存MAP中获取授权信息
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = getUsername(principals);
USERS_LOCK.readLock().lock();
try {
return this.users.get(username);
} finally {
USERS_LOCK.readLock().unlock();
}
}