1.在配置文件中定義
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/index.jsp" /> <!-- 沒有認證返回地址 --> <property name="unauthorizedUrl" value="/index2.jsp" /> <!-- 沒有授權返回地址 --> <property name="filterChainDefinitions"> <value> <!-- **代表任意子目錄 --> /login/** = anon /user/** = authc,roles[admin] /test/** = authc,perms[測試用的lkkk] </value> </property> </bean>
2.在數據庫中定義
<bean id="chainDefinitionSectionMetaSource" class="com.fyh.www.shiro.ChainDefinitionSectionMetaSource"> <property name="filterChainDefinitions"> <!-- 定義默認的url權限 --> <value> /login/** = anon </value> </property> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/index.jsp" /> <!-- 沒有認證返回地址 --> <property name="unauthorizedUrl" value="/index2.jsp" /> <!-- 沒有授權返回地址 --> <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource"/> </bean>
Resource.java(數據庫對應的pojo)
public class Resource implements Serializable { /** * id */ private Integer id; /** * url */ private String value; /** * 所需權限 */ private String permission;
//-----------------------getter/setter方法---------------------------//
ChainDefinitionSectionMetaSource.java(加載pojo)
} public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section> { @Autowired private ResourceDao resourceDao; private String filterChainDefinitions; /** * 默認premission 字符串格式模板 */ public static final String PREMISSION_STRING="perms[\"{0}\"]"; @Override public Section getObject() throws Exception { //獲取所有Resource List<Resource> list = resourceDao.getAll(); Ini ini = new Ini(); //加載默認的url ini.load(filterChainDefinitions); Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); //循環Resource 的url,逐個添加到section 中。section 就是filterChainDefinitionMap, //里面的鍵就是鏈接URL,值就是存在什么條件才能訪問該鏈接 for (Iterator<Resource> it = list.iterator(); it.hasNext();) { Resource resource = it.next(); //如果不為空值添加到section 中 if(StringUtils.isNotEmpty(resource.getValue()) && StringUtils.isNotEmpty(resource.getPermission())) { section.put(resource.getValue(),MessageFormat.format(PREMISSION_STRING,resource.getPermission())); } } return section; } /** * 通過filterChainDefinitions 對默認的url 過濾定義 * * * @param filterChainDefinitions 默認的url 過濾定義 * */ public void setFilterChainDefinitions(String filterChainDefinitions) { this.filterChainDefinitions = filterChainDefinitions; } @Override public Class<?> getObjectType() { // TODO Auto-generated method stub return null; } @Override public boolean isSingleton() { // TODO Auto-generated method stub return false; } }
dao接口
@Repository public interface ResourceDao { public List<Resource> getAll(); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.fyh.www.dao.shiro.ResourceDao" > <resultMap id="BaseResultMap" type="com.fyh.www.pojo.shiro.Resource" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="value" property="value" jdbcType="VARCHAR" /> <result column="permission" property="permission" jdbcType="VARCHAR" /> </resultMap> <select id="getAll" resultMap="BaseResultMap" > select id,value,permission from TB_RESOURCE </select> </mapper>
數據庫結構
3.在注解上定義
開啟注解(添加如下配置文件)
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>
@Controller @RequestMapping(value = "/test") public class TestController { @RequestMapping(value = "/test.action") public String test(Model model) { return SysContant.FRONT_PAGE+"NewFile1"; } @RequestMapping("/test2") @RequiresPermissions("account:create") public String testAnnotation(){ return SysContant.FRONT_PAGE+"NewFile1"; } }
可是為什么不生效呢,今天我就來說說這事兒。
我們知道Shiro的注解授權是利有Spring的AOP實現的。在程序啟動時會自動掃描作了注解的Class,當發現注解時,就自動注入授權代碼實現。也就是說,要注入授權控制代碼,第一處必須要讓框架要可以掃描找被注解的Class 。
applicationContext.xml一般配置注解掃描將@controller注解拉入黑名單
<context:component-scan base-package="com.fyh.www" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
apringmvc.xml中配置注解掃描一般只掃描@controller注解
<context:component-scan base-package="com.fyh.www.controller" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
而我們的Srping項目在ApplicationContext.xml中一般是不掃描Controller的,所以也就無法讓寫在Controller中的注解授權生效了。因此正確的作法是將這配置放到springmvc的配置文件中.這樣Controller就可以通過注解授權了。
不過問題來了,通過上面的配置Controller是可以通過注解授權了,但是Services中依然不能通過注解授權。雖然說,如果我們在Controller控制了授權,那么對於內部調用的Service層就可以不再作授權,
但也有例外的情況,比如Service除了給內部Controller層調用,還要供遠程SOAP調用,那么就需要對Service進行授權控制了。同時要控制Controller和Service,那么采用相同的方式,我們可以在ApplicationContext.xml中配置類同的配置,以達到相同的效果。
applicationContext.xml中的配置為:
<bean id="serviceAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="serviceAuthorizationAttributeSourceAdvisor" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>
apringmvc.xml中的配置為:
<bean id="controllerAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
<bean id="controllerAuthorizationAttributeSourceAdvisor" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>
此時,我們在同一個項目中配置了兩個,DefaultAdvisorAutoProxyCreator 和AuthorizationAttributeSourceAdvisor.需要給它們指定不同的ID。
