shiro 过滤器

一.OncePerRequestFilter

作用:保证一次请求过滤器只执行一次。

核心逻辑(doFilter):每次调用filter后,在req中put(filtername,true),下次调用前先判断req.get(filtername)是否为true,如果是true,执行其他过滤器。如果为false,执行doFilterInternal。

public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
        if ( request.getAttribute(alreadyFilteredAttributeName) != null ) {
            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);
            }
        }
    }

 

二.AdviceFilter

作用:aop实现。

核心逻辑(doFilterInternal):preHandle 前置,executeChain执行过滤链,postHandle后置,cleanup异常。preHandle 主要执行认证和授权,只有返回true之后才能继续执行执行链操作。postHandle无具体实现,cleanup无具体实现。

public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        Exception exception = null;

        try {

            boolean continueChain = preHandle(request, response);
            if (log.isTraceEnabled()) {
                log.trace("Invoked preHandle method.  Continuing chain?: [" + continueChain + "]");
            }

            if (continueChain) {
                executeChain(request, response, chain);
            }

            postHandle(request, response);
            if (log.isTraceEnabled()) {
                log.trace("Successfully invoked postHandle method");
            }

        } catch (Exception e) {
            exception = e;
        } finally {
            cleanup(request, response, exception);
        }
    }

三.PathMatchingFilter

作用:匹配需要shiro认证的url

核心逻辑(preHandle,isFilterChainContinued):

  1.pathsMatch(path, request)匹配成功后执行isFilterChainContinued。

  2.isFilterChainContinued中执行onPreHandle(isEnabled为true)。

    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {

        if (this.appliedPaths == null || this.appliedPaths.isEmpty()) {
            if (log.isTraceEnabled()) {
                log.trace("appliedPaths property is null or empty.  This Filter will passthrough immediately.");
            }
            return true;
        }

        for (String path : this.appliedPaths.keySet()) {
            // If the path does match, then pass on to the subclass implementation for specific checks
            //(first match 'wins'):
            if (pathsMatch(path, request)) {
                log.trace("Current requestURI matches pattern '{}'.  Determining filter chain execution...", path);
                Object config = this.appliedPaths.get(path);
                return isFilterChainContinued(request, response, path, config);
            }
        }

        //no path matched, allow the request to go through:
        return true;
    }
private boolean isFilterChainContinued(ServletRequest request, ServletResponse response,
                                           String path, Object pathConfig) throws Exception {

        if (isEnabled(request, response, path, pathConfig)) { //isEnabled check added in 1.2
            if (log.isTraceEnabled()) {
                log.trace("Filter '{}' is enabled for the current request under path '{}' with config [{}].  " +
                        "Delegating to subclass implementation for 'onPreHandle' check.",
                        new Object[]{getName(), path, pathConfig});
            }
            //The filter is enabled for this specific request, so delegate to subclass implementations
            //so they can decide if the request should continue through the chain or not:
            return onPreHandle(request, response, pathConfig);
        }

        if (log.isTraceEnabled()) {
            log.trace("Filter '{}' is disabled for the current request under path '{}' with config [{}].  " +
                    "The next element in the FilterChain will be called immediately.",
                    new Object[]{getName(), path, pathConfig});
        }
        //This filter is disabled for this specific request,
        //return 'true' immediately to indicate that the filter will not process the request
        //and let the request/response to continue through the filter chain:
        return true;
    }

 四.AccessControlFilter

作用:定义访问资源逻辑

核心逻辑(onPreHandle):isAccessAllowed是否允许访问  onAccessDenied不允许访问的操作,均无具体实现。

    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
    }

 五.AuthenticationFilter

作用:实现了允许访问的逻辑,定义了isAccessAllowed逻辑

protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = getSubject(request, response);
        return subject.isAuthenticated();
    }

六.AuthenticatingFilter

作用:进行授权和认证

核心逻辑:

  1.isAccessAllowed,在分类的逻辑中增加是否是loginurl和是否主动允许(isPermissive)

    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return super.isAccessAllowed(request, response, mappedValue) ||
                (!isLoginRequest(request, response) && isPermissive(mappedValue));
    }

  2.cleanup,AdviceFilter当父类doFilterInternal报错时,判断是否是UnauthenticatedException,如果时执行onAccessDenied

    protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException {
        if (existing instanceof UnauthenticatedException || (existing instanceof ServletException && existing.getCause() instanceof UnauthenticatedException))
        {
            try {
                onAccessDenied(request, response);
                existing = null;
            } catch (Exception e) {
                existing = e;
            }
        }
        super.cleanup(request, response, existing);

    }

  3.createToken。创建Token方法

  4.executeLogin。登录。onLoginSuccess,onLoginFailure登录成功或者失败的回调,未实现。

protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        AuthenticationToken token = createToken(request, response);
        if (token == null) {
            String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
                    "must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }
        try {
            Subject subject = getSubject(request, response);
            subject.login(token);
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            return onLoginFailure(token, e, request, response);
        }
    }

 

  上述的filter是shiro最基本的filter,一般继承AuthenticatingFilter,可满足实际需求。最核心的方法preHandle ,isAccessAllowed,onAccessDenied。

综上,继承AuthenticatingFilter,写一个shiroFilter时。可以重写createToken、isAccessAllowed、executeLogin、onAccessDenied。其中createToken定义token类型,isAccessAllowed定义允许访问条件,onAccessDenied定义拒绝访问进行相关操作后,根据操作结果是否允许访问,一般内置一个executeLogin。isAccessAllowed、executeLogin、onAccessDenied都返回true才能进入下一个过滤器,进而对资源进行访问。

 

posted @ 2020-10-10 15:38  Rogerd  阅读(447)  评论(0)    收藏  举报