在使用shiro的过程中,项目常会遇到安全拦截权限重定义或资源重载问题。简单研究下了,对之前的shiro做了修改,完成对于数据库方式记录资源权限信息的初始载入及运行过程中重载。
shiro配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd" default-lazy-init="true"> <description>Shiro安全配置</description> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroDbRealm" /> </bean> <bean id="shiroDbRealm" class="com.xxx.security.shiro.ShiroDbRealm"></bean> <!-- Shiro Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login" /> <property name="successUrl" value="/" /> <!-- 读取自定义权限内容--> <property name="filterChainDefinitions" value="#{shiroFilerChainManager.loadFilterChainDefinitions()}"/> <property name="filters"> <map> <entry key="authc"> <bean class="com.xxx.security.shiro.MyFormAuthenticationFilter"></bean> </entry> <entry key="roles"> <bean class="org.apache.shiro.web.filter.authz.RolesAuthorizationFilter"></bean> </entry> </map> </property> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
新增了一个ShiroFilerChainManager来管理过来策略加载
package com.dc.trtit.security.shiro;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.dc.flamingo.core.utils.StrUtils;
import com.xxx.security.entity.Resource;
import com.xxx.security.entity.RoleResource;
import com.xxx.security.service.ResourceService;
import com.xxx.security.service.RoleResourceService;
/**
* 安全过滤链管理器
* @author lee
*
*/
@Component("shiroFilerChainManager")
@Transactional(readOnly=true)
public class ShiroFilerChainManager {
private static final Logger log = LoggerFactory.getLogger(ShiroFilerChainManager.class);
@Autowired
private ResourceService resourceService;
@Autowired
private RoleResourceService roleResourceService;
@Autowired
private ShiroFilterFactoryBean shiroFilterFactoryBean;
private static String filterChainDefinitions = "/login = authc \r\n /logout = logout \r\n /static/** = anon \r\n /uploadImages/** = anon \r\n";
//注意/r/n前不能有空格
private static final String CRLF= "\r\n";
/**
* 加载拦截信息
* @return
*/
public String loadFilterChainDefinitions() {
List<Resource> rlist = resourceService.findAll();
List<RoleResource> rrList = roleResourceService.findAll();
Map<String, Set<String>> rolePermMap = new HashMap<String, Set<String>>();
for (RoleResource rr : rrList) {
String pageUrl = rr.getResource().getPageUrl();
Set<String> permRoles = rolePermMap.get(pageUrl);
if (permRoles == null) {
permRoles = new HashSet<String>();
}
permRoles.add(rr.getRole().getRid());
rolePermMap.put(pageUrl, permRoles);
}
StringBuffer cdBuffer = new StringBuffer();
cdBuffer.append(filterChainDefinitions);
cdBuffer.append(CRLF);
for (Resource resource : rlist) {
if (!resource.isNoPage()) {
if (Resource.TYPE_ANON == resource.getType()) {
cdBuffer.append(resource.getPageUrl()+"= anon");
cdBuffer.append(CRLF);
} else if (Resource.TYPE_ROLE == resource.getType()) {
cdBuffer.append(resource.getPageUrl()+"= roles[" + StrUtils.join(rolePermMap.get(resource.getPageUrl()), ",") + "]");
cdBuffer.append(CRLF);
}
}
}
cdBuffer.append("/** = authc");
return cdBuffer.toString();
}
/**
* 重载过滤链
*/
public void reloadFilterChains() {
AbstractShiroFilter shiroFilter = null;
try {
shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
} catch (Exception e) {
log.error("getShiroFilter from shiroFilterFactoryBean error!", e);
throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
}
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
// 清空老的权限控制
manager.getFilterChains().clear();
shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
shiroFilterFactoryBean.setFilterChainDefinitions(loadFilterChainDefinitions());
// 重新构建生成
Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue().trim().replace(" ", "");
manager.createChain(url, chainDefinition);
}
log.info("=======重新载入安全拦截信息=====");
}
}
这样就可以在web中调用重载了
/**
* 重置资源拦截
* @return
*/
@RequestMapping("/reloadFilter")
@ResponseBody
public AjaxResult reloadFilter(){
shiroFilerChainManager.reloadFilterChains();
return AjaxResult.successResult();
}
附两个资源及权限类
/**
* 资源
* @author lee
*
*/
@Entity
@Table(name = "ss_resource")
public class Resource extends IdEntity{
private static final long serialVersionUID = -5064018692683391175L;
public static final int TYPE_ANON = 0; //无权限
public static final int TYPE_USER = 1; //需登录
public static final int TYPE_ROLE = 2; //需角色
public static final String NOPAGE = "#";//此项无页面(为存菜单准备)
private String name; //名称
private String pageUrl; //链接地址
private Long parentId; //父级权限项
private Integer menuItem; //菜单项标识
private Integer type; //类型(公共、用户、角色)
private Integer orderNum; //排序号
@Entity
@Table(name = "ss_role")
public class RoleInfo extends IdEntity{
private static final long serialVersionUID = -3040190054032341166L;
private String rid;
private String name;
@Entity
@Table(name = "ss_role_resource")
public class RoleResource extends IdEntity{
private static final long serialVersionUID = 7352229649267533262L;
private RoleInfo role; //角色
private Resource resource; //权限