shiro安全控制目錄
shiro容器在啟動(dòng)的時(shí)候會(huì)默認(rèn)加載一個(gè)ini文件该押,里面有核心的默認(rèn)配置裙犹,當(dāng)然也有對(duì)應(yīng)的類,當(dāng)然在實(shí)際運(yùn)用中象对,我們可以通過查詢數(shù)據(jù)庫黑忱,將數(shù)據(jù)放入到InI對(duì)象中,動(dòng)態(tài)的進(jìn)行shiro的配置勒魔。
1. 源碼引來的思考
一般我們配置shiro主過濾鏈?zhǔn)侨缦屡渲玫母ι罚瑢tring類型注入到filterChainDefinitions屬性中。
<!-- Shiro主過濾器本身功能十分強(qiáng)大,其強(qiáng)大之處就在于它支持任何基于URL路徑表達(dá)式的冠绢、自定義的過濾器的執(zhí)行 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--shiro的核心安全接口抚吠,這是屬性是必須的-->
<property name="securityManager" ref="securityManager"/>
<!-- 要求登錄時(shí)的鏈接,非必須的屬性,默認(rèn)會(huì)自動(dòng)尋找Web工程根目錄下的"/login.jsp"頁面 -->
<property name="loginUrl" value="/login/init"></property>
<!-- 用戶訪問未對(duì)其授權(quán)的資源時(shí),所顯示的連接 -->
<property name="unauthorizedUrl" value="/pages/error/403.jsp"/>
<!--定義過濾器鏈-->
<property name="filterChainDefinitions">
<value>
<!--Shiro過濾器鏈的配置-->
/login/init/** = anon <!-- 對(duì)于登錄相關(guān)不進(jìn)行鑒權(quán) -->
/login/login/** = anon <!-- 對(duì)于登錄相關(guān)不進(jìn)行鑒權(quán) -->
/static/** = anon <!-- 靜態(tài)資源不進(jìn)行鑒權(quán) -->
/** = user
</value>
</property>
<property name="filters">
<map>
<entry key="user" value-ref="userFilter"></entry>
</map>
</property>
</bean>
<!--自定義攔截器-->
<bean id="userFilter" class="com.springmvc.common.filter.SystemUserFilter"/>
而在源碼中,實(shí)際上是創(chuàng)建了Ini.section(實(shí)際上是一個(gè)Map<String,String>) [組件]
對(duì)象弟胀,然后調(diào)用了 setFilterChainDefinitionMap(section);
方法楷力。那么我們可以自定義一個(gè)Ini.section
對(duì)象(無需在XML中進(jìn)行配置,可以動(dòng)態(tài)配置過濾器鏈)孵户,然后set注入到filterChainDefinitionMap
中呀弥雹。
shiro的filterChainDefinitions屬性源碼配置:
public void setFilterChainDefinitions(String definitions) {
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);
}
//將設(shè)置的Ini.Section保存到FilterChainDefinitionMap中。
setFilterChainDefinitionMap(section);
}
傳入的definitions值:
/login/init/** = anon
/login/login/** = user
/static/** = anon
/** = user
2. 動(dòng)態(tài)配置過濾器鏈
Spring-FactoryBean學(xué)習(xí)(更靈活的創(chuàng)建bean的方式)
Spring的XML配置文件將對(duì)象交由Spring管理的原理是:通過反射機(jī)制創(chuàng)建出對(duì)象延届,再交由Spring容器管理剪勿。那么我們在代碼中若想將Bean注入到容器中,我們可以new出對(duì)象來方庭。在調(diào)用對(duì)象的set方法或者構(gòu)造方法完成屬性注入厕吉。
為什么動(dòng)態(tài)配置過濾器鏈呢?
一般shiro的權(quán)限控制原理就是
實(shí)現(xiàn)
AuthorizingRealm
類械念,實(shí)現(xiàn)里面的鉤子方法doGetAuthenticationInfo() 認(rèn)證回調(diào)方法头朱,每次登陸時(shí)調(diào)用;doGetAuthorizationInfo()授權(quán)查詢方法龄减,當(dāng)使用注解 @RequiresPermissions進(jìn)行權(quán)限控制時(shí)回調(diào)项钮,判斷用戶是否含有該權(quán)限。本質(zhì)上就是AOP的體現(xiàn)希停。但是通過給每個(gè)權(quán)限方法加注解烁巫,代碼比較死板。所以若是可以將權(quán)限信息在項(xiàng)目啟動(dòng)的時(shí)候宠能,配置在過濾器鏈中(自定義過濾器鏈可參考:shiro(8)-shiro過濾器+自定義過濾器)亚隙。方式就像授權(quán)攔截器一樣,/user/**=perms["user:create"]违崇,那么就可以舍棄權(quán)限標(biāo)簽的用法阿弃。
關(guān)鍵點(diǎn)就是如何動(dòng)態(tài)的獲取
user:create
權(quán)限信息诊霹。并且默認(rèn)的perms授權(quán)器要求滿足所有的權(quán)限,才可放行渣淳。故我們需要自定義一個(gè)過濾器脾还,滿足任一權(quán)限,便可放行入愧。
1. 自定義授權(quán)攔截器myPermissionFilter:滿足任一權(quán)限便可放行
代碼可參考:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
2. 自定義授權(quán)攔截器myAuthcFilter:針對(duì)上送的請(qǐng)求鄙漏,進(jìn)行用戶認(rèn)證(可以在代碼中使用getSubject(request, response).login(token);
進(jìn)行用戶登錄)
如何動(dòng)態(tài)配置過濾器鏈呢?
1. 方式一:使用@Bean注解
//讀取配置文件中的(自定義的) ShiroFilter鏈配置
@Value("${shiro.filterChainDefinitions}")
private String filterChainDefinitions;
@Bean
public Ini.Section section(){
//自定義過濾器鏈名稱
String restPermissionString = "myAuthcFilter,myPermissionFilter[{0}]";
//加載默認(rèn)的url過濾定義
Ini ini = new Ini();
//加載XML配置中的filterChainDefinitions配置
ini.load(this.filterChainDefinitions);
//配置Map<String,String>
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
List<MyResource> resList = MyResourceService.queryResourcList(query);
// 將自定義url過濾添加到section中
for (MyResourceres : resList) {
if(StringUtils.isNotBlank(res.getResKey()) && StringUtils.isNotBlank(res.getResUrl())) {
if(!section.containsKey(res.getResKey())) {
section.put(res.getResUrl(), MessageFormat.format(restPermissionString, res.getResKey()));
}
}
}
section.put("/**", "myAuthcFilter");
return section;
}
2. 方式二:使用FactoryBean<Ini.Section>創(chuàng)建對(duì)象
public class ChainDefinitionSectionMetaSource implements FactoryBean<Section> {
@Autowired
private SysRescService sysRescService;
/**
* 默認(rèn)url過濾定義(shiro過濾器的filterChainDefinitions屬性)
*/
@Value("${shiro.filterChainDefinitions}")
private String filterChainDefinitions;
/**
* 設(shè)置默認(rèn)url過濾定義
*
* @param filterChainDefinitions
*/
public void setFilterChainDefinitions(String filterChainDefinitions) {
this.filterChainDefinitions = filterChainDefinitions;
}
@Override
public Section getObject() throws Exception {
//自定義過濾器鏈名稱
String restPermissionString = "myAuthcFilter,myPermissionFilter[{0}]";
// 加載默認(rèn)的url過濾定義
Ini ini = new Ini();
ini.load(this.filterChainDefinitions);
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
List<MyResource> resList = MyResourceService.queryResourcList(query);
// 將自定義url過濾添加到section中
for (MyResourceres : resList) {
if(StringUtils.isNotBlank(res.getResKey()) && StringUtils.isNotBlank(res.getResUrl())) {
if(!section.containsKey(res.getResKey())) {
// /order/query myAuthcFilter,myPermissionFilter[sysuser_list]砂客。/order/query路徑訪問的情況下泥张,必須經(jīng)過認(rèn)證,并且有sysuser_list的權(quán)限
section.put(res.getResUrl(), MessageFormat.format(restPermissionString, res.getResKey()));
}
}
}
section.put("/**", "myAuthcFilter");
return section;
}
@Override
public Class<?> getObjectType() {
return Section.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
靈活的創(chuàng)建出復(fù)雜的bean對(duì)象后鞠值,通過XML將其交由Spring管理媚创。(需要注意的是:即使class參數(shù)后面是FactoryBean<T>對(duì)象,但是這個(gè)Bean彤恶,卻是InI.section類型钞钙。)
<!--自定義ChainDefinitionSectionMetaSource-->
<bean id="section" class="com.system.shiro.ChainDefinitionSectionMetaSource">
<property name="filterChainDefinitions">
<value>
<!-- Shiro 過濾鏈的定義 -->
/login/** = anon <!-- 對(duì)于登錄相關(guān)不進(jìn)行鑒權(quán) -->
/register/** = anon <!-- 對(duì)于注冊相關(guān)不進(jìn)行鑒權(quán) -->
/static/** = anon <!-- 靜態(tài)資源不進(jìn)行鑒權(quán) -->
</value>
</property>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,這個(gè)屬性是必須的 -->
<property name="securityManager" ref="securityManager"/>
<property name="unauthorizedUrl" value="/error/403"/>
<!--由于filterChainDefinitionMap創(chuàng)建比較復(fù)雜,而且需要和數(shù)據(jù)庫交互(靈活)声离,故若是在配置文件中創(chuàng)建芒炼,那么繁雜而又死板。故采用FactoryBean在代碼中創(chuàng)建Bean术徊。-->
<property name="filterChainDefinitionMap" ref="section" />
<!--自定義攔截器-->
<property name="filters">
<map>
<entry key="myAuthcFilter" value-ref="myAuthcFilter"/>
<entry key="myPermissionFilter" value-ref="myPermissionFilter"/>
</map>
</property>
</bean>