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才能进入下一个过滤器,进而对资源进行访问。

浙公网安备 33010602011771号