当前位置:   article > 正文

解决shiro1.10.0登录过滤器执行2次的问题_shiro-all-1.10.0

shiro-all-1.10.0

本来以为就是一个简单的版本升级, 改下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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面说法解决办法, 下面说一下为啥突然需要这么搞才能解决问题.

跟一下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());
        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

而这个方法调用者就在下面

    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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

从方法名称上可以看出来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);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上面代码第四行, 增加了&& filterOncePerRequest 判断, 这个值就是通过ShiroFilterConfiguration > ShiroFilterFactoryBean一路传进来的, 而且他是在构造ShiroFilterFactoryBean之后执行的, 比自定义Filter的构造时间要晚, 所以尝试在自定义过滤器的构造方法或者postxxx, afterxxx之类的方法中去设置为true都是没用的.

所以只能是构造ShiroFilterFactoryBean对象时, 设置其配置属性来解决问题.

也就是说以前OncePerRequestFilter过滤器子类型默认只执行一次, 现在不是了, 现在可以通过全局配置来选择是否启用OncePerRequestFilter的只执行一次机制.

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/570317
推荐阅读
相关标签
  

闽ICP备14008679号