Shiro权限刷新
一、权限刷新的需求背景
在实际应用中,用户的权限可能会因为多种原因而发生变化,如用户角色的调整、权限的授予或撤销等。如果系统不能及时地反映这些变化,就可能导致安全漏洞或功能受限。因此,Shiro框架提供了权限刷新的机制,以确保系统的安全性和功能的完整性。
二、权限刷新的实现方式
-
通过重新加载权限配置:
- Shiro允许开发者在权限配置发生变化时,重新加载权限配置。这通常涉及到修改权限配置文件或数据库中的权限信息,并调用Shiro框架提供的API来重新加载这些配置。
- 例如,在Shiro的Spring Boot集成中,可以通过调用
ShiroFilterFactoryBean
的setFilterChainDefinitionMap
方法来重新设置权限过滤链。
-
通过清除缓存:
- Shiro在认证和授权过程中会使用缓存来提高性能。然而,当用户权限发生变化时,这些缓存信息可能会变得过时。
- 因此,Shiro提供了清除缓存的机制。开发者可以在修改用户权限后,调用Shiro的API来清除相关的认证和授权缓存,从而确保权限刷新的有效性。
- 例如,在自定义的Realm中,可以通过调用
getAuthenticationCache().remove
和getAuthorizationCache().remove
方法来清除特定用户的认证和授权缓存。
-
通过动态构建权限过滤器:
- Shiro支持动态构建权限过滤器,这意味着开发者可以在运行时根据用户的权限信息来构建过滤器链。
- 当用户权限发生变化时,可以重新构建过滤器链以反映这些变化。
- 这通常涉及到获取当前的权限信息、构建新的过滤器链,并将其应用到Shiro的过滤器管理器中。
三、权限刷新的注意事项
-
同步性:
- 在多用户并发访问的场景下,需要确保权限刷新的同步性,以避免因权限信息不一致而导致的安全问题。
-
性能:
- 频繁的权限刷新可能会对系统性能产生影响。因此,需要在确保安全性的前提下,合理地控制权限刷新的频率。
-
异常处理:
- 在权限刷新过程中,可能会遇到各种异常情况,如数据库连接失败、配置文件解析错误等。因此,需要做好异常处理,确保系统的稳定性和可用性。
MyShiroRealm
// 清空 当前认证用户权限缓存
public void clearMyCachedAuthorizationInfo(){
clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
// 清空所有用户权限缓存
public void clearAllCacheAuthorizationInfo(){
if (this.isAuthorizationCachingEnabled()){// 权限缓存是否可用
Cache<Object, AuthorizationInfo> cache = null;
CacheManager cacheManager = this.getCacheManager();
if (cacheManager != null){
String cacheName = this.getAuthorizationCacheName();// 获得权限缓存
cache = cacheManager.getCache(cacheName);// 获得权限缓存
}
if (cache != null){
cache.clear();// 清空
}
}
}
权限刷新方法
public Map loadFilterChainDefinitions() {
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();// 必须使用LinkedHashMap(有序集合)
filterChainDefinitionMap.put("/css/**","anon");
filterChainDefinitionMap.put("/fonts/**","anon");
filterChainDefinitionMap.put("/images/**","anon");
filterChainDefinitionMap.put("/js/**","anon");
filterChainDefinitionMap.put("/localcss/**","anon");
filterChainDefinitionMap.put("/localjs/**","anon");
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("/logout","logout");// 注销过滤器,自动注销
// 配置需要特点权限才能访问的资源(URL)
// 动态授权
List<SRight> rights = roleMapper.findAllRights();
for (SRight right : rights) {
if (right.getRightUrl() != null && !right.getRightUrl().trim().equals("")){
filterChainDefinitionMap.put(right.getRightUrl(),"perms[" + right.getRightCode() + "]");
System.out.println("动态授权:" + right.getRightText());
}
}
// 配置认证访问:其他资源(URL)必须认证通过才能访问
filterChainDefinitionMap.put("/**","authc");// 必须放在过滤器链的最后面
return filterChainDefinitionMap;
}
public void reloadFilterChainDefinitions() {
try {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
ServletContext servletContext = request.getSession().getServletContext();
AbstractShiroFilter shiroFilter = (AbstractShiroFilter) WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getBean("shiroFilterFactory");
synchronized (shiroFilter){
// 获取过滤管理器
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
// 清空初始权限权限
manager.getFilterChains().clear();
// 重新加载动态权限,配置权限验证规则
Map<String, String> chains = loadFilterChainDefinitions();
// System.out.println("chains--------" + chains);
for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue().trim().replace("","");
manager.createChain(url, chainDefinition);
}
System.out.println("更新权限成功!!");
}
}catch (Exception e){
e.printStackTrace();
}
}