4.Realm(数据处理,交互)
2015-09-03 16:54
127 查看
上一章我们讲完了CacheManager,我们这一章讲的是Realm.
Realm是一个Security组件,它主要职责是通过各种手段(JDBC、hibernate、FILE IO..)从数据库(关系数据库、NOSQL、文件..)中访问应用程序的用户的验证信息(账户密码),授权信息(资源路径)。然后根据这些信息来操作用户的登陆验证操作,和访问资源文件的授权操作。
一般不直接实现该接口,而是继承他的子类之一。如:AuthenticatingRealm(登陆验证数据操作)、AuthorizingRealm(授权数据操作)
![](http://img.blog.csdn.net/20150906172922707)
1.Realm
2.CachingRealm
3.AuthenticatingRealm
4.AuthorzaingRealm
后面的几个Realm简单讲下就好了,我觉得不是什么重点
5.SimpleAccountRealm
SimpleAccountRealm可以理解为个小数据库,里面存放了从shiro从Ini或者Properties中加载的用户数据(用户名、密码、角色、资源)
6.TextConfigurationRealm
TextConfigurationRealm继承SimpleAccountRealm,该类主要提供用户的账户密码 和 角色资源的字符串的分隔规则,
提供公共的方法(特定规则分隔字符串,然后把分隔后得到的数据存入到父类SimpleAccountRealm的相对应的
users Map或roles map中)让子类继承使用.
7.IniRealm
IniRealm继承TextConfigurationRealm,该类主要是从Ini中获得属于[users]和[roles]的字符串数据,然后传给父类TextConfigurationRealm,
父类TextConfigurationRealm对字符串按规则进行切分,然后存入到父类SimpleAccountRealm的相对应的users Map或roles map中)
让子类继承使用.
8.PropertiesRealm
PropertiesRealm继承TextConfigurationRealm,如果加载文件的类型是 “file:” 则该类提供了动态修改Propertis配置文件,
默认每10秒检查一次是否配置已修改,如果是则重新加载.该类主要是从propertis中获得属于”user.”和”role.”的字符串数据,
然后把他们拼接为特定格式(和ini的string一样的格式),然后传给父类TextConfigurationRealm。同上.
还有几个Relam实现,我也不是很懂
AbstractLdapRealm和JndiLdapRealm,不过归根到底都是从Realm加载所需得数据
Realm是一个Security组件,它主要职责是通过各种手段(JDBC、hibernate、FILE IO..)从数据库(关系数据库、NOSQL、文件..)中访问应用程序的用户的验证信息(账户密码),授权信息(资源路径)。然后根据这些信息来操作用户的登陆验证操作,和访问资源文件的授权操作。
一般不直接实现该接口,而是继承他的子类之一。如:AuthenticatingRealm(登陆验证数据操作)、AuthorizingRealm(授权数据操作)
1.Realm
[code]//Realm接口 public interface Realm { //Realm在应用内唯一的名字 String getName(); //判断当前Realm是否支持该AuthenticationToken,如果支持则true,否则false.如果为false,则不会继续往下执行登录验证 boolean supports(AuthenticationToken token); //根据token(用户名,密码)信息从底层数据库中获取相对应的用户信息,如果底层数据库不存在该用户的信息,则返回null, AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; }
2.CachingRealm
[code]//CachingRealm CacheManagerAware,和Realm,是Realm接口最底层的抽象实现,主要为其子类提供CacheManager支持 public abstract class CachingRealm implements Realm, Nameable, CacheManagerAware, LogoutAware { private static final Logger log = LoggerFactory.getLogger(CachingRealm.class); //如果实例化了多个realm,那么则用这个来做为Realm的CacheManager里面的Cache的名字的计数.防止多个Realm使用同一个缓存Cache private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); private String name; private boolean cachingEnabled; private CacheManager cacheManager; public CachingRealm() { this.cachingEnabled = true; //获取类名 + INSTANCE_COUNT 的计数作为缓存名字 this.name = getClass().getName() + "_" + INSTANCE_COUNT.getAndIncrement(); } public CacheManager getCacheManager() { return this.cacheManager; } //设置cacheManager,减少直接与底层数据库交互次数来提升性能。默认cacheManager为null public void setCacheManager(CacheManager cacheManager) { this.cacheManager = cacheManager; afterCacheManagerSet(); } //是否启用缓存设置,默认为true。如果你的底层数据库都是基于内存操作的(所有的用户信息,授权信息都保存在内存中了),那么可以设置为false,因为直接操作内存是很快的。 public boolean isCachingEnabled() { return cachingEnabled; } public void setCachingEnabled(boolean cachingEnabled) { this.cachingEnabled = cachingEnabled; } public String getName() { return name; } public void setName(String name) { this.name = name; } //Template method应该被子类实现。对SetCacheManager做后置处理 protected void afterCacheManagerSet() { } //该方法会清掉关于该用户的缓存,如果子类想重写这个方法,得保证首先调用父类的该方法. public void onLogout(PrincipalCollection principals) { clearCache(principals); } //根据PrincipalCollection 清理相对应的用户的缓存信息 protected void clearCache(PrincipalCollection principals) { if (!CollectionUtils.isEmpty(principals)) { doClearCache(principals); log.trace("Cleared cache entries for account with principals [{}]", principals); } } //子类重写该方法,执行真正的缓存删除操作 protected void doClearCache(PrincipalCollection principals) { } //根据Realm名从PrincipalCollection中获取该Realm的Principal,如果为空的话,则获取PrimaryPrincipal() protected Object getAvailablePrincipal(PrincipalCollection principals) { Object primary = null; if (!CollectionUtils.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; } }
3.AuthenticatingRealm
[code]/** Authentication Caching 如果你的应用架构是基于 REST 或者 Soap的,那么你每次请求过来都需要进行身份验证,这时,可以启用AuthenticationInfo的缓存机制。避免频繁的和底层数据库进行交互。 考虑到兼容性问题(shiro1.1及更早版本),默认不启用该功能.你可以根据setAuthenticationCachingEnabled=true来启用该功能。 如果你启用缓存功能,考虑到安全性问题,返回的AuthenticationInfo的credentials应该是加密的。 Authentication Cache Invalidation on Logout 如果authentication缓存是启用的,则在用户执行退出时候,会删除之前缓存的该用户的authentication data。 为了保证authentication data能在用户执行退出时候成功删除,getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)和getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)的返回值应该是一样的才对。否则,authentication data只能交由底层的cacheManager的实现来管理删除(根据某种策略,如:timeToIdle or timeToLive (TTL)) **/ public abstract class AuthenticatingRealm extends CachingRealm implements Initializable { private static final Logger log = LoggerFactory.getLogger(AuthenticatingRealm.class); //区分多个Realm实例,不共用同一个缓存key(也就是不共用同一个缓存) private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); //realm缓存名字的后缀 private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = ".authenticationCache"; //密码匹配器,用来匹配用户的输入的密码(经过加密后)和数据库里的密码进行匹配 private CredentialsMatcher credentialsMatcher; //authenticationInfo的缓存池,由cacheManager管理 private Cache<Object, AuthenticationInfo> authenticationCache; //是否启用缓存 private boolean authenticationCachingEnabled; //authenticationInfo缓存名字 private String authenticationCacheName; //用来判断当前Realm是否支持该AuthenticationToken private Class<? extends AuthenticationToken> authenticationTokenClass; public AuthenticatingRealm() { this(null, new SimpleCredentialsMatcher()); } public AuthenticatingRealm(CacheManager cacheManager) { this(cacheManager, new SimpleCredentialsMatcher()); } public AuthenticatingRealm(CredentialsMatcher matcher) { this(null, matcher); } public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { authenticationTokenClass = UsernamePasswordToken.class; //默认不启用缓存,考虑向后兼容性 this.authenticationCachingEnabled = false; int instanceNumber = INSTANCE_COUNT.getAndIncrement(); //组合authenticationCacheName this.authenticationCacheName = getClass().getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX; if (instanceNumber > 0) { //区分多个Realm实例,不共用同一个缓存key(也就是不共用同一个缓存) this.authenticationCacheName = this.authenticationCacheName + "." + instanceNumber; } if (cacheManager != null) { setCacheManager(cacheManager); } if (matcher != null) { setCredentialsMatcher(matcher); } } //获取当前的密码验证器 public CredentialsMatcher getCredentialsMatcher() { return credentialsMatcher; } //设置密码验证器,默认是SimpleCredentialsMatcher public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { this.credentialsMatcher = credentialsMatcher; } //获取当前Realm所支持的AuthenticationToken。默认的值是UsernamePasswordToken,因为90%的Realms使用的是username/password authentication,不管是什么协议 (jdbc,ldap,http..) public Class getAuthenticationTokenClass() { return authenticationTokenClass; } public void setAuthenticationTokenClass(Class<? extends AuthenticationToken> authenticationTokenClass) { this.authenticationTokenClass = authenticationTokenClass; } //设置Authentication的Cache缓存池,如果没有设置过,且isAuthenticationCachingEnabled=true,则可以从cacheManager中获取当前Realm实例的缓存池 public void setAuthenticationCache(Cache<Object, AuthenticationInfo> authenticationCache) { this.authenticationCache = authenticationCache; } //获取当前Realm实例的缓存池 public Cache<Object, AuthenticationInfo> getAuthenticationCache() { return this.authenticationCache; } //获取AuthenticationCacheName,然后根据该名字从cacheManager中查找Cache public String getAuthenticationCacheName() { return this.authenticationCacheName; } public void setAuthenticationCacheName(String authenticationCacheName) { this.authenticationCacheName = authenticationCacheName; } //判断当前Realm的缓存是否开启 public boolean isAuthenticationCachingEnabled() { return this.authenticationCachingEnabled && isCachingEnabled(); } //设置当前Realm支持缓存。同时设置CacheRealm的CachingEnabled=true @SuppressWarnings({"UnusedDeclaration"}) public void setAuthenticationCachingEnabled(boolean authenticationCachingEnabled) { this.authenticationCachingEnabled = authenticationCachingEnabled; if (authenticationCachingEnabled) { setCachingEnabled(true); } } //设置当前Realm实例在应用内的唯一名字 public void setName(String name) { super.setName(name); String authcCacheName = this.authenticationCacheName; //这能设置名字一次,后面再设置名字就不会成功了(这样做的目的有可能是在spring配置了修改后有意义的缓存名字后,防止用户再次修改缓存名,否则会使得过去使用该缓存名的cache缓存失效,不再有Realm指引调用) 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_AUTHORIZATION_CACHE_SUFFIX; } } /*-------------------------------------------- | M E T H O D S | ============================================*/ //判断当前Relam是否支持该token(比较token和该Realm设置的AuthenticationToken) public boolean supports(AuthenticationToken token) { return token != null && getAuthenticationTokenClass().isAssignableFrom(token.getClass()); } //根据配置来初始化AuthenticationCache public final void init() { //trigger obtaining the authorization cache if possible getAvailableAuthenticationCache(); onInit(); } //子类重写该模板方法,该方法被init()调用 protected void onInit() { } //设置了CacheManager之后,马上调用getAvailableAuthenticationCache来初始化当前Realm的Authentication缓存 protected void afterCacheManagerSet() { //trigger obtaining the authorization cache if possible getAvailableAuthenticationCache(); } //获取一个有效的Authentication缓存池,如果缓存池为null且当前开启Authentication缓存池,则初始化Authentication缓存池 private Cache<Object, AuthenticationInfo> getAvailableAuthenticationCache() { Cache<Object, AuthenticationInfo> cache = getAuthenticationCache(); boolean authcCachingEnabled = isAuthenticationCachingEnabled(); if (cache == null && authcCachingEnabled) { cache = getAuthenticationCacheLazy(); } return cache; } //延迟初始化Authentication的缓存池,如果该缓存池为null 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; } //从AuthenticationInfo缓存池中根据AuthenticationToken的principle key取出相对应的缓存 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; } //如果AuthenticationInfo缓存池启用且缓存池Cache不为null,则存AuthenticationInfo到缓存池 private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) { //判断AuthenticationInfo缓存池是否启用 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) { //根据token获取AuthenticationCache的key Object key = getAuthenticationCacheKey(token); cache.put(key, info); log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info); } } //判断AuthenticationInfo缓存池是否启用 protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, AuthenticationInfo info) { return isAuthenticationCachingEnabled(); } //根据token获取AuthenticationInfo public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //首先根据token从缓存池里获取,减少和底层数据库交互 AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //如果缓存池不存在该AuthenticationInfo则从底层数据库中加载该AuthenticationInfo info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { //把从数据库中加载的AuthenticationInfo存入到缓存池中,便于下次使用 cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { //先判断用户输入的密码和底层数据库的密码是否匹配 assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return 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."); } } //根据AuthenticationToken获取AuthenticationInfo的Key protected Object getAuthenticationCacheKey(AuthenticationToken token) { //默认为AuthenticationToken的Principal return token != null ? token.getPrincipal() : null; } //获取当前Realm的Principle,这个方法主要用在获取key,然后从缓存池中删除,所以这里得保证获取到的key是和getAuthenticationCacheKey(AuthenticationToken token)获取到的key是一致的 protected Object getAuthenticationCacheKey(PrincipalCollection principals) { return getAvailablePrincipal(principals); } //重写增强父类的doClearCache,首先调用父类的doClearCache() @Override protected void doClearCache(PrincipalCollection principals) { super.doClearCache(principals); clearCachedAuthenticationInfo(principals); } //该方法的提供便于用户在修改密码时候,能够删除旧的缓存。以免继续使用旧的验证缓存 protected void clearCachedAuthenticationInfo(PrincipalCollection principals) { if (!CollectionUtils.isEmpty(principals)) { //获取AuthenticationInfo缓存池 Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache(); //cache instance will be non-null if caching is enabled: if (cache != null) { //根据PrincipalCollection获取缓存key Object key = getAuthenticationCacheKey(principals); //从缓存池中根据key移除该缓存 cache.remove(key); } } } //从底层数据库中根据token获取相对应的AuthenticationInfo protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; }
4.AuthorzaingRealm
[code]//该抽象类主要实现Authorizer接口的方法,为子类提供授权功能.如果你不需要该功能. //可以直接继承AuthenticatingRealm且实现未实现的方法和添加自己需要的功能。 public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware { private static final Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); //默认的AuthorizayionInfo缓存后缀名 private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = ".authorizationCache"; //区分多个Realm实例的缓存名,防止共用一个缓存池 private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); //AuthorizayionInfo缓存是否开启 private boolean authorizationCachingEnabled; //AuthorizayionInfo缓存池 private Cache<Object, AuthorizationInfo> authorizationCache; //AuthorizayionInfo缓存名 private String authorizationCacheName; //转换String资源值为Permission(是安全框架一个细粒度的基础组件,代表用户的一个操作行为或者访问的一个资源路径)值 private PermissionResolver permissionResolver; //转换Role为一组Perimission,方便于细粒度验证 //默认没有提供实现,需要自己实现,因为这是和底层数据库进行交互的,没有其他操作。而和底层数据库交互,不同的应用表名列名也不相同 //所以留待用户自己实现(简单来讲,即根据角色名从底层数据库中加载一组字符串资源,然后转换成Permission) private RolePermissionResolver permissionRoleResolver; /*------------------------------------------- | C O N S T R U C T O R S | ============================================*/ public AuthorizingRealm() { this(null, null); } public AuthorizingRealm(CacheManager cacheManager) { this(cacheManager, null); } public AuthorizingRealm(CredentialsMatcher matcher) { this(null, matcher); } public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { super(); if (cacheManager != null) setCacheManager(cacheManager); if (matcher != null) setCredentialsMatcher(matcher); //默认开启authorizationInfo缓存 this.authorizationCachingEnabled = true; //默认的PermissionResolver转换器 this.permissionResolver = new WildcardPermissionResolver(); int instanceNumber = INSTANCE_COUNT.getAndIncrement(); //拼接authorizationInfo缓存池key this.authorizationCacheName = getClass().getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX; if (instanceNumber > 0) { this.authorizationCacheName = this.authorizationCacheName + "." + instanceNumber; } } /*------------------------------------------- | A C C E S S O R S / M O D I F I E R S | ============================================*/ //设置Relam名字,首先调用父类的.setName(name)方法,只能设置一次()。 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; } } public void setAuthorizationCache(Cache<Object, AuthorizationInfo> authorizationCache) { this.authorizationCache = authorizationCache; } public Cache<Object, AuthorizationInfo> getAuthorizationCache() { return this.authorizationCache; } public String getAuthorizationCacheName() { return authorizationCacheName; } @SuppressWarnings({"UnusedDeclaration"}) public void setAuthorizationCacheName(String authorizationCacheName) { this.authorizationCacheName = authorizationCacheName; } //判断AuthorizationInfo是否启用缓存 public boolean isAuthorizationCachingEnabled() { //判断CachingRealm是否启用Cache功能和当前authorizationCaching是否启用 return isCachingEnabled() && authorizationCachingEnabled; } //设置AuthorizationInfo缓存功能是否启用 @SuppressWarnings({"UnusedDeclaration"}) public void setAuthorizationCachingEnabled(boolean authenticationCachingEnabled) { this.authorizationCachingEnabled = authenticationCachingEnabled; if (authenticationCachingEnabled) { //如果AuthorizationInfo缓存功能启用,则顺带设置CachingRealm的缓存功能启用 setCachingEnabled(true); } } public PermissionResolver getPermissionResolver() { return permissionResolver; } public void setPermissionResolver(PermissionResolver permissionResolver) { if (permissionResolver == null) throw new IllegalArgumentException("Null PermissionResolver is not allowed"); this.permissionResolver = permissionResolver; } public RolePermissionResolver getRolePermissionResolver() { return permissionRoleResolver; } public void setRolePermissionResolver(RolePermissionResolver permissionRoleResolver) { this.permissionRoleResolver = permissionRoleResolver; } /*-------------------------------------------- | M E T H O D S | ============================================*/ protected void onInit() { super.onInit(); //如果可能的话,初始化AuthorzaionInfo缓存池 getAvailableAuthorizationCache(); } //设置了cacheManager之后,如果可能的话,初始化AuthorzaionInfo缓存池 protected void afterCacheManagerSet() { super.afterCacheManagerSet(); //trigger obtaining the authorization cache if possible getAvailableAuthorizationCache(); } //延迟初始化AuthorzaionInfo缓存池 private Cache<Object, AuthorizationInfo> getAuthorizationCacheLazy() { if (this.authorizationCache == null) { if (log.isDebugEnabled()) { log.debug("No authorizationCache instance set. Checking for a cacheManager..."); } CacheManager cacheManager = getCacheManager(); if (cacheManager != null) { String cacheName = getAuthorizationCacheName(); if (log.isDebugEnabled()) { log.debug("CacheManager [" + cacheManager + "] has been configured. Building " + "authorization cache named [" + cacheName + "]"); } //调用cacheManager根据当前的AuthorzaionInfo缓存池的key名,获取相对应的Cache,然后关联到this.authorizationCache this.authorizationCache = cacheManager.getCache(cacheName); } else { if (log.isInfoEnabled()) { log.info("No cache or cacheManager properties have been set. Authorization cache cannot " + "be obtained."); } } } return this.authorizationCache; } //获取有效的AuthorzaionInfo缓存池,如果不存在,且可能的话,则初始化AuthorzaionInfo缓存池 private Cache<Object, AuthorizationInfo> getAvailableAuthorizationCache() { Cache<Object, AuthorizationInfo> cache = getAuthorizationCache(); if (cache == null && isAuthorizationCachingEnabled()) { cache = getAuthorizationCacheLazy(); } return cache; } //获取AuthorizationInfo(存储用户的权限资源相关的信息,资源、角色..) 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(); //如果cache不为null则从cache中加载指定用户的AuthorizationInfo if (cache != null) { if (log.isTraceEnabled()) { log.trace("Attempting to retrieve the AuthorizationInfo from cache."); } //获取指定用户的缓存池中的key Object key = getAuthorizationCacheKey(principals); //从缓存池中获取相对应的AuthorizationInfo 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 + "]"); } } } //如果缓存池中不存在指定用户的缓存的AuthorizationInfo,则从底层数据库中加载 if (info == null) { //根据principals从底层数据库加载AuthorizationInfo 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) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } Object key = getAuthorizationCacheKey(principals); //在返回AuthorizationInfo前,先把它存入到缓存中,方便下次使用 cache.put(key, info); } } return info; } protected Object getAuthorizationCacheKey(PrincipalCollection principals) { return principals; } //清除缓存AuthorizationInfo,该方法便于用户动态的修改用户的授权资源后,然后清除旧的缓存的授权资源 //防止用户继续使用旧的授权资源 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); } } //从底层数据库中加载AuthorizationInfo protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals); //组合用户权限资源的string和permission为统一的Permission,且返回 protected Collection<Permission> getPermissions(AuthorizationInfo info) { Set<Permission> permissions = new HashSet<Permission>(); if (info != null) { //先获取Permission格式的 Collection<Permission> perms = info.getObjectPermissions(); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } //转换String格式的资源为Permission格式的资源集合 perms = resolvePermissions(info.getStringPermissions()); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } //转换角色为一组Permission集合 perms = resolveRolePermissions(info.getRoles()); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } } if (permissions.isEmpty()) { //shiro源码中大量运用了Colletions的空的集合,应该是减少不必要的内存浪费 return Collections.emptySet(); } else { return Collections.unmodifiableSet(permissions); } } //迭代String格式的资源,且转换为Permission格式的资源,然后返回 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) { Permission permission = getPermissionResolver().resolvePermission(strPermission); perms.add(permission); } } return perms; } //转换一组角色为一组Permission资源 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) { //根据角色名从RolePermissionResolver中返回一组相对应的Permission集合 Collection<Permission> resolved = resolver.resolvePermissionsInRole(roleName); if (!CollectionUtils.isEmpty(resolved)) { perms.addAll(resolved); } } } return perms; } //String格式的授权判断,传入字符串Permission和当前用户PrincipalCollection public boolean isPermitted(PrincipalCollection principals, String permission) { //转换String格式的资源为Permission对象格式的 Permission p = getPermissionResolver().resolvePermission(permission); return isPermitted(principals, p); } public boolean isPermitted(PrincipalCollection principals, Permission permission) { //根据PrincipalCollection获取相对应的用户的AuthorizationInfo AuthorizationInfo info = getAuthorizationInfo(principals); return isPermitted(permission, info); } protected boolean isPermitted(Permission permission, AuthorizationInfo info) { //获取AuthorizationInfo里的所有Permission格式的资源集合 Collection<Permission> perms = getPermissions(info); if (perms != null && !perms.isEmpty()) { //迭代判断该用户的所有Permission格式的资源集合,然后进行匹配,如果匹配上直接返回true,否则false //我觉得其实这里如果用户的权限资源过多,且用户量大的时候,对系统性能有很很大影响。 //如果是根据特定的约定,如:user:create user为用户模块,则只查找user模块的资源文件,或者更细粒度点 for (Permission perm : perms) { if (perm.implies(permission)) { return true; } } } return false; } //判断一组String格式资源文件,且返回一组boolean[] 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); } //判断一组Permission格式资源文件,且返回一组boolean[] 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; } //判断一组String格式的资源,如果全部为都授权成功则true,否则false 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; } //判断一组Permission实例格式的资源,如果全部为都授权成功则true,否则false 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; } /** 下面的check和上面的is差不多,区别只是一个返回true or false,一个授权失败直接抛异常UnauthorizedException **/ public void checkPermission(PrincipalCollection subjectIdentifier, String permission) throws AuthorizationException { Permission p = getPermissionResolver().resolvePermission(permission); checkPermission(subjectIdentifier, p); } 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); } } public void checkPermissions(PrincipalCollection subjectIdentifier, String... permissions) throws AuthorizationException { if (permissions != null) { for (String permString : permissions) { checkPermission(subjectIdentifier, permString); } } } 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); } } } //判断用户是否有该角色roleIdentifier 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); } 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; } 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; } 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); } } 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); } } } //重写增强父类的doClearCache方法 @Override protected void doClearCache(PrincipalCollection principals) { //首先调用父类AuthenticatingRealm的doClaerCache方法,删除AuhtenticationInfo缓存 super.doClearCache(principals); //再调用clearCachedAuthorizationInfo方法删除AuthorizationInfo缓存 clearCachedAuthorizationInfo(principals); } }
后面的几个Realm简单讲下就好了,我觉得不是什么重点
5.SimpleAccountRealm
SimpleAccountRealm可以理解为个小数据库,里面存放了从shiro从Ini或者Properties中加载的用户数据(用户名、密码、角色、资源)
6.TextConfigurationRealm
TextConfigurationRealm继承SimpleAccountRealm,该类主要提供用户的账户密码 和 角色资源的字符串的分隔规则,
提供公共的方法(特定规则分隔字符串,然后把分隔后得到的数据存入到父类SimpleAccountRealm的相对应的
users Map或roles map中)让子类继承使用.
7.IniRealm
IniRealm继承TextConfigurationRealm,该类主要是从Ini中获得属于[users]和[roles]的字符串数据,然后传给父类TextConfigurationRealm,
父类TextConfigurationRealm对字符串按规则进行切分,然后存入到父类SimpleAccountRealm的相对应的users Map或roles map中)
让子类继承使用.
8.PropertiesRealm
PropertiesRealm继承TextConfigurationRealm,如果加载文件的类型是 “file:” 则该类提供了动态修改Propertis配置文件,
默认每10秒检查一次是否配置已修改,如果是则重新加载.该类主要是从propertis中获得属于”user.”和”role.”的字符串数据,
然后把他们拼接为特定格式(和ini的string一样的格式),然后传给父类TextConfigurationRealm。同上.
还有几个Relam实现,我也不是很懂
AbstractLdapRealm和JndiLdapRealm,不过归根到底都是从Realm加载所需得数据
相关文章推荐
- Unity3D学习笔记《Space Shooter》二
- C语言实验题——三个数排序
- 将两个数组合并并排序
- 第31-35课
- BZOJ 1026: [SCOI2009]windy数( dp )
- 已知: 每个飞机只有一个油箱, 飞机之间可以相互加油(注意是相互,没有加油机) 一箱油可供一架飞机绕地球飞半圈,问题:为使至少一架飞机绕地球一圈回到起飞时的飞机
- 检测出运动目标后提取边界 两个函数 cvFindContours和cvBoundingRect
- Windows内核编程基础篇之获得当前滴答数
- VS2010中“工具>选项中的VC++目录编辑功能已被否决”解决方法
- rdb快照持久化
- hdu 1864 最大报销额(非整数背包)
- NOI 2006 最大获利(最大权闭合)
- 寻找数组中的最大值和最小值
- iOS 应用内购买基础教程 swift篇
- 4000 swift 学习<二> if分支, for循环,
- 蓝懿让我相信0基础的学iOS
- iOS开发有用工具网站资源
- LeetCode Delete Node in a Linked List
- 黑马程序员——面向对象(继承)-第17天
- WebService的缓存机制