Shiro的配置和核心类实现原理

@Configuration
@Import({ShiroBeanConfiguration.class,
        ShiroAnnotationProcessorConfiguration.class,
        ShiroWebConfiguration.class,
        ShiroWebFilterConfiguration.class,
        ShiroRequestMappingConfig.class})
public class ShiroConfig {

    // 非注解版本
    // @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        // 以“admin”角色登录的用户
        chainDefinition.addPathDefinition("/login/**", "anon");
        chainDefinition.addPathDefinition("/admin/**", "authc, roles[ROLE_ADMIN]");

        // 具有“document:read”权限的登录用户
        chainDefinition.addPathDefinition("/docs/**", "authc, perms[sys:user:select]");

        // 所有其他路径都需要登录用户
        chainDefinition.addPathDefinition("/**", "authc");
        return chainDefinition;
    }

}

// 处理Shiro相关Bean的类,因为Shiro提供了EventBus机制,还有提供了初始化和销毁的类,用于整合Spring
class ShiroBeanConfiguration {

    // 处理Shiro的Bean初始化和销毁的后置处理器
    // 主要用来处理Destroyable,Initializable
    // 1. ((Destroyable) obj).destroy();
    // 2. ((Initializable) obj).init();
    @Bean
    @Override
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    // 事件分发器
    @Bean
    @Override
    protected EventBus eventBus() {
        return new DefaultEventBus();
    }

    // Bean的后置处理器,找Bean中是否存在shiro的@Subscribe的Bean,负责发送一步事件
    @Bean
    @Override
    public ShiroEventBusBeanPostProcessor shiroEventBusAwareBeanPostProcessor() {
        return new ShiroEventBusBeanPostProcessor(eventBus());
    }
}

// 处理授权认证注解的后置处理器
class ShiroAnnotationProcessorConfiguration {
    // 导入一个创建AOP代理对象的后置处理器
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    protected DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }

    // 导入一个人切面,为存在  new Class[] { RequiresPermissions.class, RequiresRoles.class,RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class};
    // 这些注解的类生成代理对象,并且进行拦截
    @Bean
    protected AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}

// Shiro的核心注解注册到SpringWeb中的配置,都是默认配置
class ShiroWebConfiguration {

    // 保存Subject的DAO
    @Bean
    @Override
    protected SubjectDAO subjectDAO() {
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator());
        return subjectDAO;
    }

    // 控制哪些Session需要进行持久化
    @Bean
    @Override
    protected SessionStorageEvaluator sessionStorageEvaluator() {
        return new DefaultWebSessionStorageEvaluator();
    }

    // 创建Session的工厂
    @Bean
    @Override
    protected SessionFactory sessionFactory() {
        return new SimpleSessionFactory();
    }

    // 保存Session的DAO,默认保存在内存中
    @Bean
    @Override
    protected SessionDAO sessionDAO() {
        return new MemorySessionDAO();
    }

    // Shiro中存储Session(JSSessionId)Cookie的模板,Shiro会按照这个模板存储Session的相关信息
    @Bean(name = "sessionCookieTemplate")
    @Override
    protected Cookie sessionCookieTemplate() {
        return buildCookie(
                sessionIdCookieName,
                sessionIdCookieMaxAge,
                sessionIdCookiePath,
                sessionIdCookieDomain,
                sessionIdCookieSecure,
                sessionIdCookieSameSite);
    }

    // Shiro中处理Remember-Me的Cookie的模板,Shiro会按照这个模板存储Session的相关信息
    @Bean(name = "rememberMeCookieTemplate")
    @Override
    protected Cookie rememberMeCookieTemplate() {
        return buildCookie(
                rememberMeCookieName,
                rememberMeCookieMaxAge,
                rememberMeCookiePath,
                rememberMeCookieDomain,
                rememberMeCookieSecure,
                rememberMeSameSite);
    }

    protected Cookie buildCookie(String name, int maxAge, String path, String domain, boolean secure, Cookie.SameSiteOptions sameSiteOption) {
        Cookie cookie = new SimpleCookie(name);
        cookie.setHttpOnly(true);
        cookie.setMaxAge(maxAge);
        cookie.setPath(path);
        cookie.setDomain(domain);
        cookie.setSecure(secure);
        cookie.setSameSite(sameSiteOption);
        return cookie;
    }

    // 处理RememberMe的管理器
    @Bean
    @Override
    protected RememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookieTemplate());
        return cookieRememberMeManager;
    }

    // 创建Subject的工厂
    @Bean
    @Override
    protected SubjectFactory subjectFactory() {
        return new DefaultSubjectFactory();
    }

    // 创建授权管理器
    @Bean
    @Override
    protected Authorizer authorizer() {
        ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
        if (permissionResolver != null) {
            authorizer.setPermissionResolver(permissionResolver);
        }
        if (rolePermissionResolver != null) {
            authorizer.setRolePermissionResolver(rolePermissionResolver);
        }
        return authorizer;
    }

    // 默认的认证策略,至少一个Realm处理成功
    @Bean
    @Override
    protected AuthenticationStrategy authenticationStrategy() {
        return new AtLeastOneSuccessfulStrategy();
    }

    // 认证管理器
    @Bean
    @Override
    protected Authenticator authenticator() {
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(authenticationStrategy());
        return authenticator;
    }

    // Session会话管理器
    @Bean
    @Override
    protected SessionManager sessionManager() {
        if (useNativeSessionManager) {
            return nativeSessionManager();
        }
        return new ServletContainerSessionManager();
    }

    // 本地Session管理,默认使用Servlet的HttpSession,持久化机制不太好用,如果使用Shiro内置的Session就比较方便
    protected SessionManager nativeSessionManager() {
        DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
        webSessionManager.setSessionIdCookieEnabled(sessionIdCookieEnabled);
        webSessionManager.setSessionIdUrlRewritingEnabled(sessionIdUrlRewritingEnabled);
        webSessionManager.setSessionIdCookie(sessionCookieTemplate());

        webSessionManager.setSessionFactory(sessionFactory());
        webSessionManager.setSessionDAO(sessionDAO());
        webSessionManager.setDeleteInvalidSessions(sessionManagerDeleteInvalidSessions);

        return webSessionManager;
    }

    // Shiro的核心主键,安全管理器
    @Bean
    @Override
    protected SessionsSecurityManager securityManager(List<Realm> realms) {
        SessionsSecurityManager securityManager = createSecurityManager();
        securityManager.setAuthenticator(authenticator());
        securityManager.setAuthorizer(authorizer());
        securityManager.setRealms(realms);
        securityManager.setSessionManager(sessionManager());
        securityManager.setEventBus(eventBus);
        if (cacheManager != null) {
            securityManager.setCacheManager(cacheManager);
        }
        return securityManager;
    }

    @Override
    protected SessionsSecurityManager createSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSubjectDAO(subjectDAO());
        securityManager.setSubjectFactory(subjectFactory());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    // 默认的过滤器链定义信息,创建的过滤器会引用该Bean的配置,来定义过滤器的需要拦截的路径
    @Bean
    @Override
    protected ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        chainDefinition.addPathDefinition("/**", "authc");
        return chainDefinition;
    }

    // Shiro整合SpringMVC需要使用到的路径解析工具类,因为Shiro有自己的路径规则
    @Bean
    @Override
    protected ShiroUrlPathHelper shiroUrlPathHelper() {
        return new ShiroUrlPathHelper();
    }
}

// 注册Shiro整合SpringMVC的过滤器
@Configuration
public class ShiroWebFilterConfiguration {

    // 使用FactoryBean机制注册,内部注册核心过滤器SpringShiroFilter
    @Bean
    @Override
    protected ShiroFilterFactoryBean shiroFilterFactoryBean() {
        // 默认生成SpringShiroFilter类型的过滤器
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        // 设置登录相关的属性配置
        filterFactoryBean.setLoginUrl(loginUrl);
        filterFactoryBean.setSuccessUrl(successUrl);
        filterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
        filterFactoryBean.setSecurityManager(securityManager);
        filterFactoryBean.setShiroFilterConfiguration(shiroFilterConfiguration());
        // 全局的过滤器,默认有一个为invalidRequest
        filterFactoryBean.setGlobalFilters(globalFilters());
        // 获取自定义的拦截过滤器链定义信息,这些定义的字符串最终会解析成过滤器会整到拦截器链中
        // 因此我们一般只需要定义它就能完成拦截配置,而不需要定义指定ShiroFilter
        filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
        // 自定义的过滤器的Bean
        if (filterMap != null) {
            filterFactoryBean.setFilters(filterMap);
        }
        return filterFactoryBean;
    }

    // 全局配置
    @Bean(name = "globalFilters")
    protected List<String> globalFilters() {
        // 默认存在全局的过滤器为invalidRequest
        return Collections.singletonList(DefaultFilter.invalidRequest.name());
    }
}

// 重写SpringMVC中RequestMappingHandlerMapping的URL解析器
@Configuration
public class ShiroRequestMappingConfig {
    // 重写SpringMVC中RequestMappingHandlerMapping的URL解析器
    public ShiroRequestMappingConfig(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        requestMappingHandlerMapping.setUrlPathHelper(new ShiroUrlPathHelper());
    }
}


// 注册核心过滤器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);
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
web.xml配置 因为我们是与spring进行集成的,而spring的基本就是web项目的xml文件。所以我们在web.xml中配置shiros的过滤拦截。正常情况下,我们需要将shiro的filter配置在所有的filter前面,当然和encodingFilter这个filter是不区分前后的。因为两者互相不影响的。spring-shiro.xml 这里我们将来看看spring-shiro.xml的配置,这里我采取倒叙的方式讲解,我觉的倒叙更加的有助于我们理解代码。首先我们还记得在web.xml中配置的那个filter吧,名字shiroFilter,对spring-shiro.xml配置文件就是通过这个filter展开的。首先我们在web.xml配置的过滤器实际上是配置ShiroFilterFactoryBean,所以在这里需要将ShiroFilterFactoryBean定义为shiroFilter <!-- Shiro核心安全接口,这个属性是必须的 --> <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 --> <!-- 登录成功后要跳转的连接 --> <!-- 用户访问未对其授权的资源时,所显示的连接 --> <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp --> <!-- Shiro连接约束配置,即过滤链的定义 --> <!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 --> <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 --> <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 --> <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter --> /statics/**=anon /login.html=anon /sys/schedule.html=perms[sys:schedule:save] /sys/login=anon /captcha.jpg=anon /**=authc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值