shiro實現動態許可權管理
阿新 • • 發佈:2019-01-30
用到shiro框架實現許可權控制時,根據實際要求,許可權在資料庫增刪改後都要把許可權過濾鏈變化實時更新到伺服器中。
1、配置檔案裡配置的filterchains都是靜態的,但實際開發中更多的是從資料庫中動態的獲取filterchains。
我們都知道ShiroFilterFactoryBean中的setFilterChainDefinitions()是讀取配置檔案裡預設的filterchains,所以我們的思路是重寫這個方法,才能達到我們想要的目的:
public class ShiroPermissionFactory extends ShiroFilterFactoryBean {
private PermissService permissService;
/**記錄配置中的過濾鏈*/
public static String definition="";
public PermissService getPermissService() {
return permissService;
}
public void setPermissService(PermissService permissService){
this.permissService = permissService;
}
/**
* 初始化設定過濾鏈
*/
@Override
public void setFilterChainDefinitions(String definitions) {
definition = definitions;//記錄配置的靜態過濾鏈
List<Permission> permissions = permissService.findAll();
Map<String, String> otherChains = new HashMap<String,String>();
permissions.forEach(permiss->{
//perms.add(e)
otherChains.put(permiss.getPermissionUrl(), permiss.getPermissionvalue());
});
//載入配置預設的過濾鏈
Ini ini = new Ini();
ini.load(definitions);
Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
if (CollectionUtils.isEmpty(section)) {
section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
//加上資料庫中過濾鏈
section.putAll(otherChains);
setFilterChainDefinitionMap(section);
}
}
這裡定義的一個靜態屬性definition,作用是記錄下配置檔案中的filterchains,這個屬性在等下更新許可權的時候會用到。
配置檔案如下:
<!-- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> -->
<bean id="shiroFilter" class="com.qsblgs.util.ShiroPermissionFactory">
<property name="permissService" ref="permissService"/>
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/index" />
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name="filters">
<util:map>
<entry key="session">
<bean class="com.qsblgs.system.filter.SessionFilter" />
</entry>
<entry key="captchaAuthc">
<bean class="com.qsblgs.system.filter.CaptchaFormAuthenticationFilter">
<property name="allowLoginNum" value="3" />
<property name="cookiePath" value="/qsbl" />
<property name="cookieDomain" value="localhost" />
</bean>
</entry>
<entry key="anyRole">
<bean class="com.qsblgs.system.filter.AnyRolesFilter" />
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/index.jsp = anon
/css/login.css = anon
/jeasyui/** = anon
/bootstrap/** = anon
/common/** = anon
/unauthorized.jsp = anon
/security = anon
/login = captchaAuthc
/logout = logout
</value>
</property>
</bean>
2、系統管理員在後臺更新許可權(增刪改)的時候,要保證資料庫中的filterchains同步到伺服器中。
@Service("filterChainDefinitionsService")
public class FilterChainDefinitionsServiceImpl implements FilterChainDefinitionsService {
@Autowired
private ShiroPermissionFactory permissFactory;
@Override
public void reloadFilterChains() {
synchronized (permissFactory) { //強制同步,控制執行緒安全
AbstractShiroFilter shiroFilter = null;
try {
shiroFilter = (AbstractShiroFilter) permissFactory.getObject();
PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) shiroFilter
.getFilterChainResolver();
// 過濾管理器
DefaultFilterChainManager manager = (DefaultFilterChainManager) resolver.getFilterChainManager();
// 清除許可權配置
manager.getFilterChains().clear();
permissFactory.getFilterChainDefinitionMap().clear();
// 重新設定許可權
permissFactory.setFilterChainDefinitions(ShiroPermissionFactory.definition);//傳入配置中的filterchains
Map<String, String> chains = permissFactory.getFilterChainDefinitionMap();
//重新生成過濾鏈
if (!CollectionUtils.isEmpty(chains)) {
chains.forEach((url, definitionChains) -> {
manager.createChain(url, definitionChains.trim().replace(" ", ""));
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
這裡要注意執行緒安全控制,用synchronized關鍵字。同時,可以看到前面的靜態屬性definition這裡就派上用場了。
3、在更新許可權時呼叫reloadFilterChains(),重新載入過濾鏈:
@Autowired
private FilterChainDefinitionsService definitionService;
/**
* 儲存許可權
*/
@SuppressWarnings("unchecked")
public Permission save(Permission permission){
Permission perm = super.save(permission);
definitionService.reloadFilterChains();//儲存許可權時進行重新載入許可權過濾鏈
return perm;
}
/**
* 刪除許可權
*/
public void delete(Integer pid){
super.delete(pid);
definitionService.reloadFilterChains();//重新載入許可權過濾鏈
}
這樣就可以動態的更新許可權了。shiro也是本人初學,不知是否有漏洞地方,請大家批評指導~