今天使SpringBoot+Shiro做的过程中,遇到一个让自己困惑的问题,首先抛出问题:
/auth/login=anon
/person/**=anon
/performance/**=anon
/**=authc
这些写shiro的配置文件,通过PropertyUtil去获取配置文件,PropertyUtil是通过Properties读取的,按照理想的情况下,我访问/performance/**能够匹配的接口应该是可以访问,但最后发现是不行的,笔者整整纠结了3个多小时......
纠结之后常识将performance改为performances试了一下,太神奇了,竟然可以了,这是为什么呢???(笔者甚至认为performance是Shiro或者Spring的关键字,造成这个问题,真的是这样吗?后面的研究发现笔者错了,太糗了!!!)
笔者下定决心去看看Shiro源码,一层一层调试,找到org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain方法,最后发现了问题,请看下面两张图片:
这张图是performance的图片,请看下面一张performances的图片
仔细分析后,这个地方的顺序不太一样 ,请看下面一段代码:
public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
FilterChainManager filterChainManager = getFilterChainManager();
if (!filterChainManager.hasChains()) {
return null;
}
String requestURI = getPathWithinApplication(request);
//the 'chain names' in this implementation are actually path patterns defined by the user. We just use them
//as the chain name for the FilterChainManager's requirements
for (String pathPattern : filterChainManager.getChainNames()) {
// If the path does match, then pass on to the subclass implementation for specific checks:
if (pathMatches(pathPattern, requestURI)) {
if (log.isTraceEnabled()) {
log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "]. " +
"Utilizing corresponding filter chain...");
}
return filterChainManager.proxy(originalChain, pathPattern);
}
}
return null;
}
通过这个地方可以发现第一张图中的/**可以匹配到/performance/**里面的url,代码执行到这里,符合条件,后面的就不再执行,
研究到这里,发现了问题所在,笔者使用Properties加载属性文件,Properties加载文件后将key、value放入HashMap,这样就造成了Map中的数据根据key的Hash值排序,下面就开始研究解决方案:
1、有序读取Properties文件,下面通过自定义Properties实现,详见代码:
/**
* @author Wanxian.He
*/
public class OrderProperties extends Properties {
private static final long serialVersionUID = -4627607243846121965L;
private final LinkedHashSet
有需读取配置文件的工具类:
private static OrderProperties getOrderProperties(String propertiesFilePath, String encode)
throws IOException {
OrderProperties pros = new OrderProperties();
InputStream in = PropertyUtil.class.getResourceAsStream("/" + propertiesFilePath);
if (StringUtils.isNotEmpty(encode)) {
pros.load(new InputStreamReader(in, encode));
} else {
pros.load(in);
}
in.close();
return pros;
}
/**
* 获取资源文件里面的key对应的内容
*
* @param propertiesFilePath
* @param encode
* @return
*/
public static Map getOrderValues(String propertiesFilePath, String encode) {
Map map = new LinkedHashMap();
try {
OrderProperties pros = getOrderProperties(propertiesFilePath, encode);
Set set = pros.stringPropertyNames();
for (String key : set) {
String value = pros.getProperty(key);
map.put(key, value);
}
} catch (IOException e) {
logger.error("PropertyUtil.getValue(String propertiesFilePath:" + propertiesFilePath
+ ") exception ,return null", e);
}
return map;
}
/**
* 获取资源文件里面的key对应的内容
*
* @param propertiesFilePath
* @return
*/
public static Map getOrderValues(String propertiesFilePath) {
return getOrderValues(propertiesFilePath, null);
}
2、将有需读取到的Properties文件加载到Shiro的FilterChainDefinitionMap中
Map filterMap = PropertyUtil.getOrderValues("ispim_auth.properties");
logger.error(filterMap.toString());
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
总结:Shiro进行权限认证的加载是有序的。
截止到目前终于解决这个问题,睡觉。