shiro过滤器

ShiroFilterFactoryBean实现FactoryBean,说明他是shiroFilter工厂类,他是怎么初始化能很好的工作呢?该类的入口方法是createInstance(),该方法实现了几个功能

1、创建了一个过滤器管理类FilterChainManager,该类主要管理shiro里的过滤器,里面有两个重要的属性

1.1 filters:管理全部过滤器,包括默认的身份验证和权限验证的过滤器,这些过滤器分为两组,一组是认证过滤器,有anon,authenBasic,auchc,user,一组是授权过滤器,有perms,roles,ssl,rest,port.同时也包含在xml里filters配置的自定义过滤器。在其他地方使用时都是从过滤器管理类里filters里拿的,且过滤器是单例的,整个shiro框架只维护每种类型过滤器的单例。

1.2 filterChains:过滤链。他是一个map对象,其中key就是我们请求的url,value是一个namedFilterList对象,里面存放的是与url对应的一系列过滤器。

2、将过滤器管理类设置到PathMatchingFilterChainResolver类里,该类负责路径和过滤器链的解析与匹配,根据url找到过滤器链。

@Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 登录,无权限是跳转的路径
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后跳转的路径
        shiroFilterFactoryBean.setSuccessUrl("/info");
        // 错误页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        // 配置拦截规则
        Map<String, String> filterChainMap = new LinkedHashMap<>();
        /**
         * authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器
         * @see org.apache.shiro.web.filter.authc.FormAuthenticationFilter
         * anon:它对应的过滤器里面是空的,什么都没做,可以理解为不拦截
         * @see org.apache.shiro.web.filter.authc.AnonymousFilter
         * authc:所有url都必须认证通过才可以访问;anon:所有url都都可以匿名访问
         */
  
        // 拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/user/login", "anon");
        filterChainDefinitionMap.put("/user/logout", "logout");
        // 根据用户的角色赋予相应的权限
        // filterChainDefinitionMap.put("/add", "roles[admin]");
        // filterChainDefinitionMap.put("/delete", "roles[admin]");
        // filterChainDefinitionMap.put("/delete", "roles[author]");
        filterChainDefinitionMap.put("/addPermission", "roles[author]");
        filterChainDefinitionMap.put("/add", "perms[user:add]");
        filterChainDefinitionMap.put("/delete", "perms[user:delete]");
        filterChainDefinitionMap.put("/userList", "perms[user:list]");
        // 匹配所有的路径
        // 通过Map集合组成了一个拦截器链 ,自顶向下过滤,一旦匹配,则不再执行下面的过滤
        // 如果下面的定义与上面冲突,那按照了谁先定义谁说了算
        // 一定要配置在最后
        filterChainDefinitionMap.put("/**", "authc");
        // 将拦截器链设置到shiro中
      shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    
        return shiroFilterFactoryBean;
    }

继承链

shiroFilterFactoryBean继承BeanPostProcessor和FactoryBean

1、BeanPostProcessor接口的实现

/**
     * Inspects a bean, and if it implements the {@link Filter} interface, automatically adds that filter
     * instance to the internal {@link #setFilters(java.util.Map) filters map} that will be referenced
     * later during filter chain construction.
     */
// 检查一个bean,如果它实现了filter接口,自动将该过滤器添加到内部filters map中,稍后在过滤器链的构建过程中再引用该实例(后面第4点createFilterChainManager )
    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;
            // 应用全局配置
            applyGlobalPropertiesIfNecessary(filter);
            // 将在Spring中注册(而不是在ShiroFilterFactoryBean中配置的)的Filter并入.
            // 这里面就牵扯出一个有趣的问题 : FactoryBean<T>接口的getObject方法和     BeanPostProcessor接口的postProcessBeforeInitialization的执行先后顺序?
            // (为了保证不遗漏Filter, 我们可以猜测后者必须优先于前者。)
            // 上面这个括号里面的参考下面博客的说法有一点要注意的是,打断点调试确实是postProcessBeforeInitialization先进去的但是并没有进去找到任何的filter,因为我是注解提供的filterMap,所以是在执行createFilterChainManager的时候先查找default的filter再添加我们在config类中传进去的flterMap解析filter到filterChainManager中。我猜测如果是有xml配置的话,应该是postProcessBeforeInitialization最先读取xml配置中的filter的
            // 这里先记录一下吧
            getFilters().put(beanName, filter);
        } else {
            log.trace("Ignoring non-Filter bean '{}'", beanName);
        }
        return bean;
    }

2、FactoryBean接口实现

FactoryBean就是一个工厂类的bean可以生产我们自己定义的bean并进行一些装饰

public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }
 public Class getObjectType() {
        return SpringShiroFilter.class;
    }

3、ShiroFilterFactoryBean.createInstance方法

/**
     * This implementation:
     * <ol>
     * <li>Ensures the required {@link #setSecurityManager(org.apache.shiro.mgt.SecurityManager) securityManager}
     * property has been set</li>
     * <li>{@link #createFilterChainManager() Creates} a {@link FilterChainManager} instance that reflects the
     * configured {@link #setFilters(java.util.Map) filters} and
     * {@link #setFilterChainDefinitionMap(java.util.Map) filter chain definitions}</li>
     * <li>Wraps the FilterChainManager with a suitable
     * {@link org.apache.shiro.web.filter.mgt.FilterChainResolver FilterChainResolver} since the Shiro Filter
     * implementations do not know of {@code FilterChainManager}s</li>
     * <li>Sets both the {@code SecurityManager} and {@code FilterChainResolver} instances on a new Shiro Filter
     * instance and returns that filter instance.</li>
     * </ol>
     *
     * @return a new Shiro Filter reflecting any configured filters and filter chain definitions.
     * @throws Exception if there is a problem creating the AbstractShiroFilter instance.
     */
    protected AbstractShiroFilter createInstance() throws Exception {
​
        log.debug("Creating Shiro Filter instance.");
​
        SecurityManager securityManager = getSecurityManager();
        // 创建实例之前必须设置securityManager
        if (securityManager == null) {
            String msg = "SecurityManager property must be set.";
            throw new BeanInitializationException(msg);
        }
​
        if (!(securityManager instanceof WebSecurityManager)) {
            String msg = "The security manager does not implement the WebSecurityManager interface.";
            throw new BeanInitializationException(msg);
        }
        //看下面分析4 创建默认的过滤器管理器
        FilterChainManager manager = createFilterChainManager();  -----4
​
        //Expose the constructed FilterChainManager by first wrapping it in a
        //FilterChainResolver implementation. The AbstractShiroFilter implementations
        //do not know about FilterChainManagers - only resolvers:
        //写死为PathMatchingFilterChainResolver
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        //将过滤器管理器设置到pathMatchingFilterChainResolver对象中
        chainResolver.setFilterChainManager(manager);
​
        //Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
        //FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class
        //here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
        //injection of the SecurityManager and FilterChainResolver:
        //构造SpringShiroFilter实例,由Spring管理
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

实现创建这个实例之前:

(1)必须确保SecurityManager属性已经设置了

(2)创建一个FilterChainManager实例,该实例反映了我们配置的相关过滤内容filterChainDefinitionMap

(3)用合适的方法包装FilterChainManager

(4)因为shiro filter实例不能感知到FilterChainManager,我们需要给他配置解析器FilterChainResolver

(5)一个新的shiro过滤器,他反映了所有已配置的过滤器和过滤器链定义

该方法创建过滤器管理器,同时设置到PathMatchingFilterChainResolver对象里,当有请求过来,shiro会通过PathMatchingFilterChainResolver解析得到请求的url对应的过滤器链

4、shiroFilterFactoryBean.createFilterChainManager方法

protected FilterChainManager createFilterChainManager() {
        // 这个构造函数中会将shiro默认的Filter添加到FilterChainManager中.
        // 点进去查看shiro的默认filter有哪些,见后面分析5
        DefaultFilterChainManager manager = new DefaultFilterChainManager();   ------5
        //获得shiro默认的过滤器,同时将xml里配置的loginUrl/unauthorizedUrl设置到不同过滤器里
        Map<String, Filter> defaultFilters = manager.getFilters();
        // 将ShiroFilterFactoryBean配置的一些公共属性(上面配置的loginUrl, successUrl,  unauthorizeUrl)应用到默认注册的filter上去
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }
        //Apply the acquired and/or configured filters:
        // 然后再将用户配置的Filter并入; 所以如果用户配置了与上面同名的Filter, 则会进行覆盖操作
        // 此处的getFilters();获取的是当前实例的filters属性,这个是属性值在创建默认的DefaultFilterChainManager的时候add进去的默认filter,以及在web.xml中自定义的filter(由postProcessBeforeInitialization注入)
        Map<String, Filter> filters = getFilters();
        if (!CollectionUtils.isEmpty(filters)) {
            for (Map.Entry<String, Filter> entry : filters.entrySet()) {
                String name = entry.getKey();
                Filter filter = entry.getValue();
                applyGlobalPropertiesIfNecessary(filter);
                if (filter instanceof Nameable) {
                    ((Nameable) filter).setName(name);
                }
                //'init' argument is false, since Spring-configured filters should be initialized
                // in Spring (i.e. 'init-method=blah') or implement InitializingBean:
                // spring会处理初始化问题, 所以shiro就不负责初始化了
                manager.addFilter(name, filter, false);
            }
        }
        //build up the chains:
        // 这里将处理用户配置的ShiroFilterFactoryBean.filterChainDefinitions属性
        Map<String, String> chains = getFilterChainDefinitionMap();
        if (!CollectionUtils.isEmpty(chains)) {
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                // 见下面分析7
                manager.createChain(url, chainDefinition);      -------7
            }
        }
        return manager;
    }

(1)applyGlobalPropertiesNecessary(filter);方法是将配置loginUrl,successUrl、unauthorizedUrl设置到不同过滤器里,其中loginUrl赋值到所有继承自AccessController的过滤里,successUrl赋值到所有继承自AuthenticationFilter发过滤器里,unauthorizedUrl赋值到所有继承自AUthorizationFilter的过滤器里。也可以自己设置loginUrl successUrl unauthorizedUrl,自定义赋值覆盖全局指定的

(2)读取filters配置的自定义过滤器,将他们纳入过滤器管理器里

(3)最后服务FilterChainDefinitions配置,根据配置设置每个url对应的过滤连,filterChains保存这些配置,他是一个map集合,key是url,value是过滤器组成的namedFilterList集合,当请求过来时,解析出请求路径,会从filterChains里找到url对应的过滤链,按过滤器的策略一个一个执行下去。

5、DefaultFilterChainManager()

filtelrs中缓存了所有添加的filter,filterChains则缓存了所有的filterChains,其中前者的key是filter name,value是filter,后者的key是chain name,value是NamedFilterList

private FilterConfig filterConfig;
 private Map<String, Filter> filters; //pool of filters available for creating chains
 private Map<String, NamedFilterList> filterChains; //key: chain name, value: chain
DefaultFilterChainManager manager = new DefaultFilterChainManager();
// DefaultFilterChainManager构造函数
public DefaultFilterChainManager() {
        this.addDefaultFilters(false);
    }
​
protected void addDefaultFilters(boolean init) {
        // shiro的DefaultFilter是一个枚举类,包含下面的11种启动时默认加载的filter
        DefaultFilter[] var2 = DefaultFilter.values();
        int var3 = var2.length;
        // 遍历
        for(int var4 = 0; var4 < var3; ++var4) {
          DefaultFilter defaultFilter = var2[var4];
          // 把filter添加到manager中,不需要初始化,由Spring来完成
          this.addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
        }
    }
​
public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
}

6、filterChainDefinitionMap

分析shiro如何处理spring-shiro.xml中用户配置的shiroFilterFactoryBean.filterChainDefinitions属性的

//---------- ShiroFilterFactoryBean.setFilterChainDefinitions方法
public void setFilterChainDefinitions(String definitions) {
    // 使用Ini类来解析用户配置的信息
    Ini ini = new Ini();
    ini.load(definitions);
    //did they explicitly state a 'urls' section?  Not necessary, but just in case:
    Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
    if (CollectionUtils.isEmpty(section)) {
        //no urls section.  Since this _is_ a urls chain definition property, just assume the
        //default section contains only the definitions:
        section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
    }
    // 将解析出来的结果赋值给ShiroFilterFactoryBean的filterChainDefinitionMap字段
    setFilterChainDefinitionMap(section);
}

也可以使用注解的配置方式,直接用diamante给filterChainDefinitionMap赋值即可

//将拦截器链设置到shiro中
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

7、DefaultFilterChainManager.createChain

public void createChain(String chainName, String chainDefinition) {
        // 以上面配置的filterChainDefinitions参数举例:    
        // 参数chainName形如 /admin/list**
        // 参数chainDefinition形如 authc,perms[admin:manage]
        if (!StringUtils.hasText(chainName)) {
            throw new NullPointerException("chainName cannot be null or empty.");
        }
        if (!StringUtils.hasText(chainDefinition)) {
            throw new NullPointerException("chainDefinition cannot be null or empty.");
        }
        if (log.isDebugEnabled()) {
            log.debug("Creating chain [" + chainName + "] from String definition [" + chainDefinition + "]");
        }
​
        //parse the value by tokenizing it to get the resulting filter-specific config entries
        //
        //e.g. for a value of
        //
        //     "authc, roles[admin,user], perms[file:edit]"
        //
        // the resulting token array would equal
        //
        //     { "authc", "roles[admin,user]", "perms[file:edit]" }
        //以上我们就可以看出我们所配置的ShiroFilterFactoryBean的filterChainDefinitions里的 每一行 会在这里被完整解析
        String[] filterTokens = splitChainDefinition(chainDefinition);
​
        //each token is specific to each filter.
        //strip the name and extract any filter-specific config between brackets [ ]
        for (String token : filterTokens) {
            /* toNameConfigPair的解析结果参见下面这个,摘选自官方
        Input               Result 
        
        foo                 returned[0] == foo
                            returned[1] == null 
                            
        foo[bar, baz]       returned[0] == foo
                            returned[1] == bar, baz 
        */
            String[] nameConfigPair = toNameConfigPair(token);
            //now we have the filter name, path and (possibly null) path-specific config.  Let's apply them:
            // 见分析8
            addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);    ----------8
        }
    }

8、DefaultFilterChainManager.addToChain方法

public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
        if (!StringUtils.hasText(chainName)) {
            throw new IllegalArgumentException("chainName cannot be null or empty.");
        }
        // 如果用户没有配置该filter, 则直接抛出的异常
        Filter filter = getFilter(filterName);
        if (filter == null) {
            throw new IllegalArgumentException("There is no filter with name '" + filterName +
                    "' to apply to chain [" + chainName + "] in the pool of available Filters.  Ensure a " +
                    "filter with that name/path has first been registered with the addFilter method(s).");
        }
        // 保存用户配置的url与filter之间的映射关系,注册到filter中
        applyChainConfig(chainName, filter, chainSpecificFilterConfig);
        // chainName为配置的url路径
        // 这里会以用户配置的url路径来创建一个SimpleNamedFilterList示例;  并添加到DefaultFilterChainManager内部的Map<String, NamedFilterList>类型的类级字段filterChains中(以用户配置的url路径为key——即filterChainDefinitions参数里每一行等号左边的部分)
        NamedFilterList chain = ensureChain(chainName);
        chain.add(filter);
    }

整个过程就是缓存了两张map,下面将FilterChainManager设置到PathMatchingFilterChainResolver中,PathMatchingFilterChainResolver实现了FilterChainResolver接口,该接口只定义了一个方法:

FilterChain getChain(ServletRequesr request,ServlerReponse,FilterChain originalChain);

通过解析请求来得到一个FilterChainResolver,而PathMatchingFIlterChainResolver实现了该接口,依靠了FilterChainManager中保存的chainFilters和filters这两个map来根据请求路径解析出相应的FilterChainManager,并且和originalChain组合起来使用

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        // 得到 FilterChainManager 
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }
​
        String requestURI = getPathWithinApplication(request);
​
        // chainNames就是刚定义的filterChains的keySet,也就是所有的路径集合(比如:["/resources/**","/login"])
        for (String pathPattern : filterChainManager.getChainNames()) {
​
            // 请求路径是否匹配某个 定义好的路径:
            if (pathMatches(pathPattern, requestURI)) {
                if (log.isTraceEnabled()) {
                    log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "].  " + "Utilizing corresponding filter chain...");
                }
                // 找到第一个匹配的Filter链,那么就返回一个ProxiedFilterChain
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }
​
        return null;
    }

这里返回两种情况,null或ProxiedFilrerChain,返回null并不表示中断FilterChain,而是只用originChain,而关于ProxiedFilrerChain,它实现了FilterChain,内部维护了两份filtetChain(一个是filterChain,另一个是LIst<Filter>)FilterChain也就是web.xml中注册的filter形成的FilterChain,诚意为originChain,而另一个List<Filter>则是我们在shiro中注册的Filter链了。

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (this.filters == null || this.filters.size() == this.index) {
            //we've reached the end of the wrapped chain, so invoke the original one:
            if (log.isTraceEnabled()) {
                log.trace("Invoking original filter chain.");
            }
            this.orig.doFilter(request, response);
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Invoking wrapped filter at index [" + this.index + "]");
            }
            this.filters.get(this.index++).doFilter(request, response, this);
        }
    }

他会先执行shiro中执行的filter,然后再执行web.xml中的filter,需要注意的是,需要等到originChain执行到shiroFilterFactory之后才会执行shiro中的filter链。

当这两个组件创建完毕后,该如何工作呢

protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
            throws ServletException, IOException {
​
        Throwable t = null;
​
        try {
            final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
            final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
​
            final Subject subject = createSubject(request, response);
​
            //noinspection unchecked
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    // 其实需要关心的就在这里
                    // touch一下session
                    updateSessionLastAccessTime(request, response);
                    // 执行Filter链
                    executeChain(request, response, chain);
                    return null;
                }
            });
        } catch (ExecutionException ex) {
            t = ex.getCause();
        } catch (Throwable throwable) {
            t = throwable;
        }
​
        if (t != null) {
            if (t instanceof ServletException) {
                throw (ServletException) t;
            }
            if (t instanceof IOException) {
                throw (IOException) t;
            }
            //otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one:
            String msg = "Filtered request failed.";
            throw new ServletException(msg, t);
        }
    }
跟进executeChain(...)方法:

    protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
            throws IOException, ServletException {
        FilterChain chain = getExecutionChain(request, response, origChain);
        chain.doFilter(request, response);
    }

如何得到FilterChain呢?利用刚才注册的ChainResolver

protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
        FilterChain chain = origChain;
​
        FilterChainResolver resolver = getFilterChainResolver();
        if (resolver == null) {
            log.debug("No FilterChainResolver configured.  Returning original FilterChain.");
            return origChain;
        }
​
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            log.trace("Resolved a configured FilterChain for the current request.");
            chain = resolved;
        } else {
            log.trace("No FilterChain configured for the current request.  Using the default.");
        }
​
        return chain;
    }

当resolver.getChain()返回null是,直接使用originChain,然后执行filterChain.doFilter方法。

分析以上,当浏览器发出一个请求,服务器启动,读取web.xml中的filter、filter-mapping节点后组成filterChain,对请求进行拦截,按照filter节点的定义顺序,shiro利用shiroFilter来充当一个总的拦截器来分发所有需要被shiro拦截的请求,所有shiro中还可以自定义拦截器。shiroFilter根据他在拦截器中的位置,只要执行到了就会暂停中断原FilterChain的执行,先执行shiro中定义的filter,最后执行原FilterChain

filter后配置的[]如何生效

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;
        }
​
        // appliedPaths中保存了该filter中能拦截的路径和该路径配置的key-value对,比如{key="/admin/**", value="[admin]"}
        for (String path : this.appliedPaths.keySet()) {
            // 首先是匹配路径
            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
            }
            return onPreHandle(request, response, pathConfig);
        }
​
        if (log.isTraceEnabled()) {
            // log
        }
        return true;
    }

基本也是交给onPreHandle来处理,所以一般需要验证"[]"中字符串的filter都会扩展这个方法,如AccessController

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

 public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
​
        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;
​
        if (rolesArray == null || rolesArray.length == 0) {
            //no roles specified, so nothing to check - allow access.
            return true;
        }
​
        Set<String> roles = CollectionUtils.asSet(rolesArray);
        return subject.hasAllRoles(roles);
    }

转载:https://www.cnblogs.com/waycx/p/12800393.html

读源码非常需要耐心,嗯,静心学透

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值