赞
踩
本来以为就是一个简单的版本升级, 改下pom重新打包梳理jar依赖替换下就可以, 结果发现登录请求里的createToken之类的方法每次都执行2次.
如果是普通登录请求倒也无所谓, 现在在登录过程中做了密码加密, 登录密码仅能够解析一次. 第一次进过滤器createToken解析成功, 第二次在执行createToken时解析临时密码就无效了, 所以到最后前端收到的信息都是密码无效.
这里发一下解决办法, 其实非常简单. 创建ShiroFilterFactoryBean
的时候, 给他一个ShiroFilterConfiguration
实例对象, 并且设置这个实例的setFilterOncePerRequest(true)
即可解决问题.
贴一下代码:
ShiroFilterConfiguration config = new ShiroFilterConfiguration();
config.setFilterOncePerRequest(Boolean.TRUE);
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setShiroFilterConfiguration(config);
// TODO: 这里放自定义过滤器
factoryBean.setFilters(filters);
// TODO: 这里放url过滤器映射规则
factoryBean.setFilterChainDefinitionMap(filterRuleMap);
上面说法解决办法, 下面说一下为啥突然需要这么搞才能解决问题.
跟一下ShiroFilterFactoryBean
的代码, 发现本次setShiroFilterConfiguration
之后, 这个对象主要用于下面这个方法
private void applyGlobalPropertiesIfNecessary(Filter filter) {
this.applyLoginUrlIfNecessary(filter);
this.applySuccessUrlIfNecessary(filter);
this.applyUnauthorizedUrlIfNecessary(filter);
if (filter instanceof OncePerRequestFilter) {
((OncePerRequestFilter)filter).setFilterOncePerRequest(this.filterConfiguration.isFilterOncePerRequest());
}
}
而这个方法调用者就在下面
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Filter) {
log.debug("Found filter chain candidate filter '{}'", beanName);
Filter filter = (Filter)bean;
this.applyGlobalPropertiesIfNecessary(filter);
this.getFilters().put(beanName, filter);
} else {
log.trace("Ignoring non-Filter bean '{}'", beanName);
}
return bean;
}
从方法名称上可以看出来postProcessBeforeInitialization
方法在bean初始化的时候去执行, 将自定义的登录过滤器中的setFilterOncePerRequest
设置为了ShiroFilterConfiguration
实例中给定的true
再查一下1.9.1到1.10.0的升级内容 git:1.9.1>1.10.0差异对比
发现OncePerRequestFilter
类中的核心方法
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName(); if ( request.getAttribute(alreadyFilteredAttributeName) != null && filterOncePerRequest) { log.trace("Filter '{}' already executed. Proceeding without invoking this filter.", getName()); filterChain.doFilter(request, response); } else //noinspection deprecation if (/* added in 1.2: */ !isEnabled(request, response) || /* retain backwards compatibility: */ shouldNotFilter(request) ) { log.debug("Filter '{}' is not enabled for the current request. Proceeding without invoking this filter.", getName()); filterChain.doFilter(request, response); } else { // Do invoke this filter... log.trace("Filter '{}' not yet executed. Executing now.", getName()); request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); try { doFilterInternal(request, response, filterChain); } finally { // Once the request has finished, we're done and we don't // need to mark as 'already filtered' any more. request.removeAttribute(alreadyFilteredAttributeName); } } }
上面代码第四行, 增加了&& filterOncePerRequest
判断, 这个值就是通过ShiroFilterConfiguration
> ShiroFilterFactoryBean
一路传进来的, 而且他是在构造ShiroFilterFactoryBean
之后执行的, 比自定义Filter的构造时间要晚, 所以尝试在自定义过滤器的构造方法或者postxxx, afterxxx之类的方法中去设置为true都是没用的.
所以只能是构造ShiroFilterFactoryBean
对象时, 设置其配置属性来解决问题.
也就是说以前OncePerRequestFilter
过滤器子类型默认只执行一次, 现在不是了, 现在可以通过全局配置来选择是否启用OncePerRequestFilter
的只执行一次机制.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。