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。