咱们的受权过滤器使用的是permissionsAuthorizationFilter来进行拦截。咱们能够在application-shiro中配置filter规则java
<!--商品查询须要商品查询权限 -->
/items/queryItems.action = perms[item:query]
/items/editItems.action = perms[item:edit]
测试流程:
一、在applicationContext-shiro.xml中配置filter规则web
<!--商品查询须要商品查询权限 -->
二、用户在认证经过后,请求/items/queryItems.action
三、被PermissionsAuthorizationFilter拦截,发现须要“item:query”权限
四、PermissionsAuthorizationFilter**调用realm中的doGetAuthorizationInfo获取数据库中正确的权限**
五、PermissionsAuthorizationFilter对item:query 和从realm中获取权限进行对比,若是“item:query”在realm返回的权限列表中,受权经过。spring
realm中获取认证的信息,查询出该用户对应的权限,封装到simpleAuthorizationInfo中,PermissionsAuthorizationFilter会根据对应的权限来比对。数据库
@Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { //从 principals获取主身份信息 //将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证经过填充到SimpleAuthenticationInfo中身份类型), ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal(); //根据身份信息获取权限信息 //从数据库获取到权限数据 List<SysPermission> permissionList = null; try { permissionList = sysService.findPermissionListByUserId(activeUser.getUserid()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //单独定一个集合对象 List<String> permissions = new ArrayList<String>(); if(permissionList!=null){ for(SysPermission sysPermission:permissionList){ //将数据库中的权限标签 符放入集合 permissions.add(sysPermission.getPercode()); } } /* List<String> permissions = new ArrayList<String>(); permissions.add("user:create");//用户的建立 permissions.add("item:query");//商品查询权限 permissions.add("item:add");//商品添加权限 permissions.add("item:edit");//商品修改权限 */ //.... //查到权限数据,返回受权信息(要包括 上边的permissions) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //将上边查询到受权信息填充到simpleAuthorizationInfo对象中 simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; }
在bean中咱们已经配置了:若是没有权限,那么跳转到哪一个JSP页面了apache
<!-- 经过unauthorizedUrl指定没有权限操做时跳转页面--> <property name="unauthorizedUrl" value="/refuse.jsp" />
到目前为止,如今问题又来了:编程
一、在applicationContext-shiro.xml中配置过虑器连接,须要将所有的url和权限对应起来进行配置,比较发麻不方便使用。缓存
二、每次受权都须要调用realm查询数据库,对于系统性能有很大影响,能够经过shiro缓存来解决。安全
上面的那种方法,仍是须要咱们将所有的url和权限对应起来进行配置,是比较不方便的。咱们可使用受权的另外两种方式markdown
若是要使用注解式,那么就必须在Spring中开启controller类aop支持session
<!-- 开启aop,对类代理 --> <aop:config proxy-target-class="true"></aop:config> <!-- 开启shiro注解支持 --> <bean class=" org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean>
在Controller中使用注解来进行配置就好了,就不用在咱们的application-shiro中所有集中配置了
//商品信息方法 @RequestMapping("/queryItems") @RequiresPermissions("item:query")//执行queryItems须要"item:query"权限 public ModelAndView queryItems(HttpServletRequest request) throws Exception { System.out.println(request.getParameter("id")); //调用service查询商品列表 List<ItemsCustom> itemsList = itemsService.findItemsList(null); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("itemsList", itemsList); // 指定逻辑视图名 modelAndView.setViewName("itemsList"); return modelAndView; }
当调用controller的一个方法,因为该 方法加了@RequiresPermissions(“item:query”) ,shiro调用realm获取数据库中的权限信息,看”item:query”是否在权限数据中存在,若是不存在就拒绝访问,若是存在就受权经过。
当展现一个jsp页面时,页面中若是遇到,shiro调用realm获取数据库中的权限信息,看item:update是否在权限数据中存在,若是不存在就拒绝访问,若是存在就受权经过。
针对上边受权频繁查询数据库,须要使用shiro缓存
shiro中提供了对认证信息和受权信息的缓存。shiro默认是关闭认证信息缓存的,对于受权信息的缓存shiro默认开启的。主要研究受权信息缓存,由于受权的数据量大。
用户认证经过。
该用户第一次受权:调用realm查询数据库
该用户第二次受权:不调用realm查询数据库,直接从缓存中取出受权信息(权限标识符)。
导入jar包
配置缓存管理器,注入到安全管理器中
<!-- 缓存管理器 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/> </bean>
<!-- securityManager安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="customRealm" /> <!-- 注入缓存管理器 --> <property name="cacheManager" ref="cacheManager"/> </bean>
ehcache的配置文件shiro-ehcache.xml:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!--diskStore:缓存数据持久化的目录 地址 --> <diskStore path="F:\develop\ehcache" /> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
若是用户正常退出,缓存自动清空。
若是用户非正常退出,缓存自动清空。
还有一种状况:
清除缓存:
//清除缓存 public void clearCached() { PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals(); super.clearCache(principals); }
和shiro整合后,使用shiro的session管理,shiro提供sessionDao操做 会话数据。
配置sessionManager
<!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- session的失效时长,单位毫秒 --> <property name="globalSessionTimeout" value="600000"/> <!-- 删除失效的session --> <property name="deleteInvalidSessions" value="true"/> </bean>
注入到安全管理器中
<!-- securityManager安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="customRealm" /> <!-- 注入缓存管理器 --> <property name="cacheManager" ref="cacheManager"/> <!-- 注入session管理器 --> <property name="sessionManager" ref="sessionManager" /> </bean>