Shiro核心处理类ShiroFilter创建和解析原理



// 注册核心过滤器SpringShiroFilter
public class ShiroFilterFactoryBean {
    // 创建Spring的过滤器
    public Object getObject() throws Exception {
        SecurityManager securityManager = getSecurityManager();
        // 创建过滤器链
        FilterChainManager manager = this.createFilterChainManager();
        // 创建路径的过滤器链解析器
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        // 创建过滤器
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver, getShiroFilterConfiguration());
    }

    // 创建过滤器链的管理器
    protected FilterChainManager createFilterChainManager() {
        // 创建过滤器链管理器
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        // 添加过滤器,名称为anon,authc => 对象为枚举anon对应的AnonymousFilter过滤器全类名
        Map<String, Filter> defaultFilters = manager.getFilters();
        // 设置全局属性,设置不同过滤器的属性,例如登录的url,登录成功的url
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }
        // 获取在当前ShiroFilterFactoryBean手动配置的过滤器
        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();
                // 设置全局属性,设置不同过滤器的属性,例如登录的url,登录成功的url
                applyGlobalPropertiesIfNecessary(filter);
                // 设置名称
                if (filter instanceof Nameable) {
                    ((Nameable) filter).setName(name);
                }
                // 添加该过滤器到过滤器链管理器中
                manager.addFilter(name, filter, false);
            }
        }

        // 设置全局过滤器
        manager.setGlobalFilters(this.globalFilters);

        // 构建过滤器链
        // 获取过滤器链的定义信息,也就是ShiroFilterChainDefinition中的filterChainDefinitionMap
        Map<String, String> chains = getFilterChainDefinitionMap();
        // 如果定义的url->过滤器的映射
        if (!CollectionUtils.isEmpty(chains)) {
            // 遍历所有的过滤器
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                // 用url作为key创建一个该url对应的过滤器链
                manager.createChain(url, chainDefinition);
            }
        }
        // 如果没有设置任何url的映射,创建一个默认拦截所有的过滤器链,过滤器为设置的全局过滤器,如果没有设置,则默认是一个空过滤器集合
        manager.createDefaultChain("/**");
        return manager;
    }


}

// 提供的默认的过滤器
public enum DefaultFilter {
    anon(AnonymousFilter.class),

    /**
     * authc filter.
     */
    authc(FormAuthenticationFilter.class),

    /**
     * authc basic filter.
     */
    authcBasic(BasicHttpAuthenticationFilter.class),

    /**
     * authc bearer filter.
     */
    authcBearer(BearerHttpAuthenticationFilter.class),

    /**
     * ip filter.
     */
    ip(IpFilter.class),

    /**
     * logout filter.
     */
    logout(LogoutFilter.class),

    /**
     * no session creation filter.
     */
    noSessionCreation(NoSessionCreationFilter.class),

    /**
     * perms filter.
     */
    perms(PermissionsAuthorizationFilter.class),

    /**
     * port filter.
     */
    port(PortFilter.class),

    /**
     * rest filter.
     */
    rest(HttpMethodPermissionFilter.class),

    /**
     * roles filter.
     */
    roles(RolesAuthorizationFilter.class),

    /**
     * ssl filter.
     */
    ssl(SslFilter.class),

    /**
     * user filter.
     */
    user(UserFilter.class),

    /**
     * invalid request filter.
     */
    invalidRequest(InvalidRequestFilter.class);
}

// 过滤器链管理器,内部包含了url->该url对应的过滤器集合的映射关系,在ShiroFilterChainDefinition中配置的
public class DefaultFilterChainManager implements FilterChainManager {
    // 过滤器配置,例如过滤器名称,过滤器初始化参数等等
    private FilterConfig filterConfig;

    // 过滤器名称(anon) -> 实际过滤器的映射关系(AnonymousFilter)
    // 添加过滤器,名称为anon,authc => 对象为枚举anon对应的AnonymousFilter过滤器全类名
    private Map<String, Filter> filters;

    // 全局过滤器,附加到每个过滤器链中过滤器列表
    private List<String> globalFilterNames;

    /**
     * 保存url到该url需要使用的过滤器链的映射信息
     */
    private Map<String, NamedFilterList> filterChains;

    public DefaultFilterChainManager(FilterConfig filterConfig) {
        this.filters = new LinkedHashMap<String, Filter>();
        this.filterChains = new LinkedHashMap<String, NamedFilterList>();
        this.globalFilterNames = new ArrayList<>();
        setFilterConfig(filterConfig);
        // 添加枚举中的
        addDefaultFilters(true);
    }

    // 添加默认的过滤器,都在DefaultFilter枚举中定义的
    protected void addDefaultFilters(boolean init) {
        for (DefaultFilter defaultFilter : DefaultFilter.values()) {
            // 添加过滤器,名称为anon,authc => 对象为枚举anon对应的AnonymousFilter过滤器全类名,直接实例化
            this.addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
        }
    }

    /**
     * 添加过滤器
     *
     * @param name      过滤器名称{@link DefaultFilter}的名称或者自定义过滤器名称
     * @param filter    过滤器{@link DefaultFilter}的过滤器类名实例化后的对象或者自定义过滤器名对应的过滤器对象
     * @param init      是否需要执行过滤器的init方法
     * @param overwrite 如果设置了多个相同的过滤器是否可以覆盖
     */
    protected void addFilter(String name, Filter filter, boolean init, boolean overwrite) {
        // 是否存在这个过滤器
        Filter existing = getFilter(name);
        // 如果不存在或者允许过滤器覆盖
        if (existing == null || overwrite) {
            // 如果该过滤器实现了Nameable接口,可以设置过滤器名称
            if (filter instanceof Nameable) {
                ((Nameable) filter).setName(name);
            }
            // 执行过滤器的init方法
            if (init) {
                initFilter(filter);
            }
            // 保存到过滤器链管理器中的filter列表
            this.filters.put(name, filter);
        }
    }

    // 根据过滤器名称获取对应的过滤器
    public Filter getFilter(String name) {
        return this.filters.get(name);
    }

    // 将该过滤器名称对应的过滤器对象添加到url对应的该过滤器链集合中,这样,通过url就能找到给url需要用到的所有过滤器
    public void addToChain(String url, String filterName, String chainSpecificFilterConfig) {
        // 获取该过滤器名称对应的过滤器链
        Filter filter = this.getFilter(filterName);
        // 如果没有,抛出异常,因为在创建该对象的时候,就初始化了所有的过滤器名称对应过滤器的映射关系
        // 其中还包括自定义的过滤器,在ShiroFilterFactoryBean设置的,也是过滤器名->过滤器对象的映射
        // 还有在当前
        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).");
        }
        // 应用过滤器配置
        applyChainConfig(url, filter, chainSpecificFilterConfig);
        // 创建带有名称的过滤器集合
        NamedFilterList chain = this.ensureChain(url);
        // 将该过滤器保存到过滤器集合中
        chain.add(filter);
    }

    // 创建url与该url需要使用过滤器链的映射集合
    public void createChain(String url, String chainDefinition) {
        // 首先添加每个全局过滤器
        if (!CollectionUtils.isEmpty(globalFilterNames)) {
            // 将该过滤器名称对应的过滤器对象添加到url对应的该过滤器链集合中,这样,通过url就能找到给url需要用到的所有过滤器
            globalFilterNames.stream().forEach(filterName -> addToChain(chainName, filterName));
        }
        // 解析过滤器链的定义信息,就是url -> 过滤器链的定义信息
        // 例如: (/a,"authc, roles[admin,user], perms[file:edit]")
        // 例如: (/**, "authc", "roles[admin,user]", "perms[file:edit]")
        // 其中chainDefinition为"authc", "roles[admin,user]", "perms[file:edit]",使用","分割
        // 切割为:["authc","roles[admin,user]", "perms[file:edit]"]
        String[] filterTokens = splitChainDefinition(chainDefinition);
        // 遍历所有的认证定义信息
        for (String token : filterTokens) {
            // 将角色权限表达式进行切割
            // 例如"roles[admin,user]"切割为["roles","admin,user"]
            // 其中[0]表示权限的过滤器,[1]表示需要的权限
            String[] nameConfigPair = toNameConfigPair(token);
            // 将表达成组成过滤器链,url作为过滤器链的名称
            // 将该过滤器名称对应的过滤器对象添加到url对应的该过滤器链集合中,这样,通过url就能找到给url需要用到的所有过滤器
            this.addToChain(url, nameConfigPair[0], nameConfigPair[1]);
        }
    }

    // 创建带有名称的过滤器集合,过滤器名称为url,过滤器链为一个SimpleNamedFilterList集合,内部包含多个过滤器
    protected NamedFilterList ensureChain(String url) {
        // 获取是否存在该名称的过滤器链
        NamedFilterList chain = getChain(url);
        // 如果不存在
        if (chain == null) {
            // 包含过滤器名称 + 过滤器集合(默认是空的过滤器集合,只是先创建这个集合
            // 之后在往该集合内部添加过滤器
            chain = new SimpleNamedFilterList(url);
            // 保存url到该url需要使用的过滤器链的映射信息
            this.filterChains.put(url, chain);
        }
        return chain;
    }

    public NamedFilterList getChain(String chainName) {
        return this.filterChains.get(chainName);
    }

    // 创建代理的过滤器链
    public FilterChain proxy(FilterChain original, String url) {
        // 获取该url对应的过滤器集合
        NamedFilterList configured = this.getChain(url);
        if (configured == null) {
            String msg = "There is no configured chain under the name/key [" + url + "].";
            throw new IllegalArgumentException(msg);
        }
        // 创建代理
        return configured.proxy(original) {
            return new ProxiedFilterChain(orig, this);
        }
    }
}

// 代理的过滤器链
public class ProxiedFilterChain implements FilterChain {
    // 原始的过滤器链
    private FilterChain orig;
    // 该url需要处理的过滤器集合
    private List<Filter> filters;
    // 正在执行的过滤去链下标
    private int index;

    public ProxiedFilterChain(FilterChain orig, List<Filter> filters) {
        if (orig == null) {
            throw new NullPointerException("original FilterChain cannot be null.");
        }
        this.orig = orig;
        this.filters = filters;
        this.index = 0;
    }

    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        // 如果不存在过滤器,或者过滤器集合为空
        if (this.filters == null || this.filters.size() == this.index) {
            // 直接执行原始的过滤器链
            this.orig.doFilter(request, response);
        } else {
            // 执行该url对应的过滤器集合,一一进行过滤
            this.filters.get(this.index++).doFilter(request, response, this);
        }
    }
}

// 核心过滤器详解
class SpringShiroFilter extends AbstractShiroFilter {
    protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver, ShiroFilterConfiguration filterConfiguration) {
        super();
        // 初始化SecurityManager
        if (webSecurityManager == null) {
            throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
        }
        // 设置SecurityManager
        setSecurityManager(webSecurityManager);
        // 设置Shiro过滤器的配置信息
        setShiroFilterConfiguration(filterConfiguration);
        // 设置Shiro过滤器链的解析器,将/**,aono解析为一个url->过滤器链的集合
        if (resolver != null) {
            setFilterChainResolver(resolver);
        }
    }
}

public abstract class AbstractShiroFilter extends OncePerRequestFilter {

    // 是否开启静态的SecurityManage的初始化参数配置名称
    private static final String STATIC_INIT_PARAM_NAME = "staticSecurityManagerEnabled";

    // 此过滤器使用的安全管理器
    private WebSecurityManager securityManager;

    // 过滤器链的解析器
    private FilterChainResolver filterChainResolver;

    // 是否开启静态的SecurityManage
    // SecurityUtils.setSecurityManager(getSecurityManager());
    private boolean staticSecurityManagerEnabled;

    // 默认不开启SecurityUtils.setSecurityManager(getSecurityManager());
    protected AbstractShiroFilter() {
        this.staticSecurityManagerEnabled = false;
    }

    // 过滤器初始化
    protected final void onFilterConfigSet() throws Exception {
        // 初始化SecurityManager参数的配置,通过这个配置确定是否可以通过SecurityUtils.setSecurityManager(getSecurityManager())获取SecurityManager
        this.applyStaticSecurityManagerEnabledConfig();
        // init操作,默认无逻辑
        this.init();
        // 设置SecurityManager
        this.ensureSecurityManager();
        // SecurityUtils.setSecurityManager(getSecurityManager())获取SecurityManager
        if (isStaticSecurityManagerEnabled()) {
            SecurityUtils.setSecurityManager(getSecurityManager());
        }
    }

    // 初始化SecurityManager参数的配置,通过这个配置确定是否可以通过SecurityUtils.setSecurityManager(getSecurityManager())获取SecurityManager
    private void applyStaticSecurityManagerEnabledConfig() {
        String value = getInitParam(STATIC_INIT_PARAM_NAME);
        if (value != null) {
            boolean success = Boolean.parseBoolean(value);
            if (success) {
                setStaticSecurityManagerEnabled(success);
            }
        }
    }

    // 将原生的request封装为Shiro的request对象
    // 这样就可方便的与Shiro内置的Session等等机制进行整合
    protected ServletRequest wrapServletRequest(HttpServletRequest orig) {
        return new ShiroHttpServletRequest(orig, getServletContext(), isHttpSessions());
    }

    // 将原生的request封装为Shiro的request对象
    protected ServletRequest prepareServletRequest(ServletRequest request, ServletResponse response, FilterChain chain) {
        ServletRequest toUse = request;
        if (request instanceof HttpServletRequest) {
            HttpServletRequest http = (HttpServletRequest) request;
            toUse = wrapServletRequest(http);
        }
        return toUse;
    }

    // 将原生的response封装为ShiroHttpServletResponse的response对象
    protected ServletResponse wrapServletResponse(HttpServletResponse orig, ShiroHttpServletRequest request) {
        return new ShiroHttpServletResponse(orig, getServletContext(), request);
    }

    // 将原生的response封装为ShiroHttpServletResponse的response对象
    protected ServletResponse prepareServletResponse(ServletRequest request, ServletResponse response, FilterChain chain) {
        ServletResponse toUse = response;
        // 如果不是使用HttpSession才需要包装,因为Web环境默认就是使用HttpSession
        // 如果要使用Shiro原生的shiro,则包装一下,就是提供Servlet整合Shiro的支持
        if (!isHttpSessions() && (request instanceof ShiroHttpServletRequest) && (response instanceof HttpServletResponse)) {
            toUse = wrapServletResponse((HttpServletResponse) response, (ShiroHttpServletRequest) request);
        }
        return toUse;
    }

    // 创建Subject对象
    protected WebSubject createSubject(ServletRequest request, ServletResponse response) {
        return new WebSubject.Builder(getSecurityManager(), request, response).buildWebSubject();
    }

    // 如果使用的是Shiro原生的Session,更下一下最后访问的时间
    protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response) {
        // 如果使用的是Shiro原生的Session,更下一下最后访问的时间
        if (!isHttpSessions()) {
            Subject subject = SecurityUtils.getSubject();
            if (subject != null) {
                Session session = subject.getSession(false);
                if (session != null) {
                    session.touch();
                }
            }
        }
    }

    // 过滤方法,就是doFilter,从OncePerRequestFilter继承
    protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException {

        // 包装Request对象
        final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
        // 包装Response对象
        final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
        // 创建Subject对象
        final Subject subject = createSubject(request, response);

        // 让创建的Subject与当前线程关联
        // 让SecurityUtils.getSubject()生效
        subject.execute((Callable<Void>) () -> {
            // 更新Session最后访问时间
            this.updateSessionLastAccessTime(request, response);
            // 执行过滤器链
            this.executeChain(request, response, chain);
            return null;
        });
    }

    // 获取可执行的过滤器链
    protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
        FilterChain chain = origChain;
        // 获取过滤器链解析器,如果不存在解析器,直接返回原过滤器链
        FilterChainResolver resolver = getFilterChainResolver();
        if (resolver == null) {
            return origChain;
        }
        /**
         * 解析该过滤器链
         * 该解析器的原理为: 将该请求url到{@link DefaultFilterChainManager}过滤器链管理器中找到之前保存的url->该url需要使用的过滤器集合列表
         * 然后创建一个代理的过滤器链来执行,实际上引用的就是该url对应的这个过滤器集合,如果该url不存在过滤器,则调用原始的过滤器链执行
         */
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            chain = resolved;
        }
        // 返回解析好的过滤器链,如果存在url对应需要使用的过滤器集合,那么这个过滤器链就是一个代理的过滤器链
        return chain;
    }

    class FilterChainResolver {
        // 解析url对应的过滤器链
        public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
            // 获取过滤器链管理器
            DefaultFilterChainManager filterChainManager = getFilterChainManager();
            // 如果不存在过滤器链,不处理
            if (!filterChainManager.hasChains()) {
                return null;
            }
            // 获取请求url
            final String requestURI = getPathWithinApplication(request);
            final String requestURINoTrailingSlash = removeTrailingSlash(requestURI);

            // 遍历所有的过滤器链名称,就是url pattern
            for (String pathPattern : filterChainManager.getChainNames()) {
                // 当前过滤器的url pattern是否匹配上当前请求的url
                if (pathMatches(pathPattern, requestURI)) {
                    // 匹配上了,创建该url对应的代理过滤器链
                    return filterChainManager.proxy(originalChain, pathPattern);
                } else {
                    // 去除最后一个"/"在来匹配一下
                    // 用户可以使用requestURI + "/"来简单地绕过链式过滤器,绕过shiro保护
                    pathPattern = removeTrailingSlash(pathPattern);
                    // 匹配上了,创建该url对应的代理过滤器链
                    if (pathMatches(pathPattern, requestURINoTrailingSlash)) {
                        return filterChainManager.proxy(originalChain, pathPattern);
                    }
                }
            }
            return null;
        }

    }

    // 执行该请求url对应的过滤器链
    protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException {
        // 获取可执行的过滤器链,该过滤器链是一个代理了Shiro多个过滤器的过滤器链
        FilterChain chain = this.getExecutionChain(request, response, origChain);
        // 执行过滤器链
        chain.doFilter(request, response);
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shiro核心对象是Subject、SecurityManager、Realm和Session等。 1. Subject:表示当前用户,可以是一个人、一个程序或是一种服务。Subject是Shiro核心对象,它封装了当前用户的所有安全操作,包括身份验证、授权等。在Web应用中,每个请求都会被封装成一个Subject对象。 2. SecurityManager:表示整个安全框架的核心,负责管理所有Subject、Realm和权限信息等。SecurityManager是Shiro核心对象之一,它是整个安全框架的入口,负责协调各个对象之间的关系,处理安全操作的请求。 3. Realm:表示安全数据源,负责获取身份验证、授权等信息,并将其传递给SecurityManager。Realm是Shiro核心对象之一,它负责获取安全数据,包括用户的身份、角色和权限等信息,然后将这些信息传递给SecurityManager进行处理。 4. Session:表示用户会话,用于存储用户的状态信息,如登录状态、访问历史等。Session是Shiro的一个重要对象,它允许开发者将一些状态信息存储在用户会话中,以便在不同的请求之间共享。 Shiro处理流程大致如下: 1. 用户发起请求,请求到达Web服务器。 2. Shiro Filter拦截请求,将请求转发给SecurityManager。 3. SecurityManager根据配置的Realm获取用户的身份、角色和权限等信息。 4. SecurityManager将用户身份信息传递给Authenticator进行身份验证,验证成功后将用户信息存储在Subject中。 5. SecurityManager根据用户的角色和权限信息判断用户是否有权限访问请求资源。 6. 如果用户有权限访问请求资源,SecurityManager将请求转发给Web服务器,Web服务器将响应结果返回给用户。 7. 如果用户没有权限访问请求资源,SecurityManager将返回未授权的错误信息。 需要注意的是,Shiro处理流程是可扩展的,开发者可以通过自定义Realm、Filter、Authenticator等对象来实现自己的安全策略。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值