ruoyi的spring cloud项目详解(十)

ruoyi的spring cloud项目详解(九)-CSDN博客

接着上篇文章我们一起学习

com/ruoyi/common/utils/spring/SpringContextHolder.java

package com.ruoyi.common.utils.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * spring工具类 方便在非spring管理环境中获取bean
 * 
 * @author ruoyi
 */
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{
    /** Spring应用上下文环境 */
    private static ConfigurableListableBeanFactory beanFactory;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
    {
        SpringUtils.beanFactory = beanFactory;
    }

    /**
     * 获取对象
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws org.springframework.beans.BeansException
     *
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException
    {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 获取类型为requiredType的对象
     *
     * @param clz
     * @return
     * @throws org.springframework.beans.BeansException
     *
     */
    public static <T> T getBean(Class<T> clz) throws BeansException
    {
        T result = (T) beanFactory.getBean(clz);
        return result;
    }

    /**
     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
     *
     * @param name
     * @return boolean
     */
    public static boolean containsBean(String name)
    {
        return beanFactory.containsBean(name);
    }

    /**
     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
     *
     * @param name
     * @return boolean
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
    {
        return beanFactory.isSingleton(name);
    }

    /**
     * @param name
     * @return Class 注册对象的类型
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
    {
        return beanFactory.getType(name);
    }

    /**
     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
     *
     * @param name
     * @return
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
    {
        return beanFactory.getAliases(name);
    }
}

以下是对这段代码的分析:

一、功能

  • 提供在非 Spring 管理的环境中方便地获取 Spring 容器中的 bean 的方法。

二、主要功能

  1. 实现BeanFactoryPostProcessor接口,在 Spring 容器初始化 bean 工厂后执行特定的处理逻辑。
  2. 存储 Spring 的ConfigurableListableBeanFactory,以便在后续方法中使用。
  3. 提供一系列静态方法用于获取 bean、检查 bean 是否存在、判断 bean 的单例性、获取 bean 的类型和别名等。

三、代码逻辑

  1. 使用@Component注解将这个类标记为一个 Spring 组件,以便被 Spring 容器管理。
  2. 定义静态变量beanFactory用于存储ConfigurableListableBeanFactory
  3. 实现BeanFactoryPostProcessor接口的postProcessBeanFactory方法,在这个方法中,将传入的ConfigurableListableBeanFactory赋值给静态变量beanFactory,这样在其他静态方法中就可以使用这个 bean 工厂。
  4. getBean(String name)方法:根据给定的 bean 名称从 bean 工厂中获取 bean 的实例,并进行类型转换。
  5. getBean(Class<T> clz)方法:根据给定的类型从 bean 工厂中获取 bean 的实例。
  6. containsBean(String name)方法:检查 bean 工厂中是否包含给定名称的 bean。
  7. isSingleton(String name)方法:判断给定名称的 bean 是否是单例的。
  8. getType(String name)方法:获取给定名称的 bean 的类型。
  9. getAliases(String name)方法:获取给定名称的 bean 的别名。

四、用途

  1. 在一些非 Spring 管理的环境中,比如某些工具类或独立的模块中,可以使用SpringUtils提供的静态方法方便地获取 Spring 容器中的 bean,而无需直接依赖 Spring 的上下文。
  2. 可以用于在运行时动态地获取特定类型的 bean,进行一些灵活的业务处理。
  3. 方便进行一些依赖注入的检查和调试工作。

以下是对这段代码按代码块进行分析:

一、导入和注解部分

package com.ruoyi.common.utils.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

  • 导入了一些与 Spring 相关的类和接口,包括用于处理 bean 工厂的BeanFactoryPostProcessorConfigurableListableBeanFactory,以及用于处理异常的BeansExceptionNoSuchBeanDefinitionException
  • 使用@Component注解将这个类标记为一个 Spring 组件,以便被 Spring 容器管理。

二、类定义和静态变量部分

@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
    /** Spring应用上下文环境 */
    private static ConfigurableListableBeanFactory beanFactory;

  • 定义了一个名为SpringUtils的类,并使用@Component注解使其成为一个可被 Spring 容器管理的组件。
  • 声明了一个静态变量beanFactory,用于存储ConfigurableListableBeanFactory,这是 Spring 容器的一种类型,用于管理 bean 的定义和实例。

三、实现接口的方法部分

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    SpringUtils.beanFactory = beanFactory;
}

  • 实现了BeanFactoryPostProcessor接口的postProcessBeanFactory方法。这个方法在 Spring 容器初始化 bean 工厂后被调用。
  • 在这个方法中,将传入的ConfigurableListableBeanFactory赋值给静态变量beanFactory,以便在其他静态方法中使用这个 bean 工厂。

四、获取 bean 的方法部分

@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
    return (T) beanFactory.getBean(name);
}

public static <T> T getBean(Class<T> clz) throws BeansException {
    T result = (T) beanFactory.getBean(clz);
    return result;
}

  • 提供了两个静态方法getBean用于获取 Spring 容器中的 bean。
  • 第一个方法getBean(String name)根据给定的 bean 名称从 bean 工厂中获取 bean 的实例,并进行类型转换。使用了@SuppressWarnings("unchecked")注解来抑制未经检查的类型转换警告。
  • 第二个方法getBean(Class<T> clz)根据给定的类型从 bean 工厂中获取 bean 的实例。

五、检查 bean 存在性和属性的方法部分

public static boolean containsBean(String name) {
    return beanFactory.containsBean(name);
}

public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
    return beanFactory.isSingleton(name);
}

public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
    return beanFactory.getType(name);
}

public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
    return beanFactory.getAliases(name);
}

  • containsBean(String name)方法用于检查 bean 工厂中是否包含给定名称的 bean。
  • isSingleton(String name)方法用于判断给定名称的 bean 是否是单例的。如果 bean 定义不存在,会抛出NoSuchBeanDefinitionException异常。
  • getType(String name)方法用于获取给定名称的 bean 的类型。如果 bean 定义不存在,会抛出NoSuchBeanDefinitionException异常。
  • getAliases(String name)方法用于获取给定名称的 bean 的别名。如果 bean 定义不存在,会抛出NoSuchBeanDefinitionException异常。

我们接着研究

com/ruoyi/common/xss/XssFilter.java

package com.ruoyi.common.xss;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;

/**
 * 防止XSS攻击的过滤器
 * 
 * @author ruoyi
 */
public class XssFilter implements Filter
{
    /**
     * 排除链接
     */
    public List<String> excludes = new ArrayList<>();

    /**
     * xss过滤开关
     */
    public boolean enabled = false;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
        String tempExcludes = filterConfig.getInitParameter("excludes");
        String tempEnabled = filterConfig.getInitParameter("enabled");
        if (StringUtils.isNotEmpty(tempExcludes))
        {
            String[] url = tempExcludes.split(",");
            for (int i = 0; url != null && i < url.length; i++)
            {
                excludes.add(url[i]);
            }
        }
        if (StringUtils.isNotEmpty(tempEnabled))
        {
            enabled = Boolean.valueOf(tempEnabled);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException
    {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if (handleExcludeURL(req, resp))
        {
            chain.doFilter(request, response);
            return;
        }
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
        chain.doFilter(xssRequest, response);
    }

    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
    {
        if (!enabled)
        {
            return true;
        }
        if (excludes == null || excludes.isEmpty())
        {
            return false;
        }
        String url = request.getServletPath();
        for (String pattern : excludes)
        {
            Pattern p = Pattern.compile("^" + pattern);
            Matcher m = p.matcher(url);
            if (m.find())
            {
                return true;
            }
        }
        return false;
    }

    @Override
    public void destroy()
    {

    }
}

以下是对这段代码的分析:

一、功能

  • 提供一个过滤器来防止跨站脚本攻击(XSS)。

二、主要功能

  1. 可配置排除特定 URL 的 XSS 过滤。
  2. 根据配置开关决定是否启用 XSS 过滤。
  3. 对请求进行 XSS 过滤处理后再传递给后续的处理链。

三、代码逻辑

  1. 定义成员变量和构造函数
    • public List<String> excludes = new ArrayList<>();:用于存储需要排除进行 XSS 过滤的 URL 列表。
    • public boolean enabled = false;:XSS 过滤的开关,默认关闭。
  2. 初始化方法(init)
    • 从过滤器的配置参数中读取excludesenabled的值。
    • 如果excludes参数有值,将其分割成数组,然后添加到排除列表中。
    • 如果enabled参数有值,将其转换为布尔值并设置过滤开关。
  3. 过滤方法(doFilter)
    • ServletRequestServletResponse转换为HttpServletRequestHttpServletResponse
    • 调用handleExcludeURL方法判断当前请求的 URL 是否需要排除在 XSS 过滤之外。
    • 如果需要排除,直接将请求传递给后续处理链并返回。
    • 如果不需要排除,创建一个XssHttpServletRequestWrapper对象包装原始请求,对请求进行 XSS 过滤处理,然后将包装后的请求传递给后续处理链。
  4. 排除 URL 处理方法(handleExcludeURL)
    • 如果 XSS 过滤开关关闭,返回true,表示不进行过滤。
    • 如果排除列表为空,返回false,表示不排除任何 URL。
    • 遍历排除列表,使用正则表达式匹配当前请求的 URL,如果匹配成功,返回true,表示该 URL 需要排除在 XSS 过滤之外。
    • 如果没有任何 URL 匹配成功,返回false,表示该 URL 需要进行 XSS 过滤。
  5. 销毁方法(destroy)
    • 目前为空方法,可用于在过滤器被销毁时进行清理操作。

四、用途

  1. 在 Web 应用中,通过配置这个过滤器,可以有效地防止 XSS 攻击。
  2. 可以根据实际需求配置排除特定 URL 的 XSS 过滤,例如对于一些信任的内部接口或者不需要进行 XSS 过滤的资源请求。
  3. 通过设置过滤开关,可以方便地在不同环境下开启或关闭 XSS 过滤功能。

以下是对这段代码按代码块进行讲解:

一、包声明和导入部分

package com.ruoyi.common.xss;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
  • 声明了包名com.ruoyi.common.xss
  • 导入了一系列用于处理 Servlet 过滤器、正则表达式匹配、输入输出流以及自定义工具类StringUtils所需的类和接口。

二、过滤器类定义部分

public class XssFilter implements Filter {
    /**
     * 排除链接
     */
    public List<String> excludes = new ArrayList<>();

    /**
     * xss过滤开关
     */
    public boolean enabled = false;

  • 定义了一个名为XssFilter的类,实现了Filter接口,表示这是一个 Servlet 过滤器。
  • 声明了一个List<String>类型的成员变量excludes,用于存储需要排除进行 XSS 过滤的 URL 列表。
  • 声明了一个boolean类型的成员变量enabled,作为 XSS 过滤的开关,默认值为false,表示关闭过滤。

三、初始化方法部分

@Override
public void init(FilterConfig filterConfig) throws ServletException {
    String tempExcludes = filterConfig.getInitParameter("excludes");
    String tempEnabled = filterConfig.getInitParameter("enabled");
    if (StringUtils.isNotEmpty(tempExcludes)) {
        String[] url = tempExcludes.split(",");
        for (int i = 0; url!= null && i < url.length; i++) {
            excludes.add(url[i]);
        }
    }
    if (StringUtils.isNotEmpty(tempEnabled)) {
        enabled = Boolean.valueOf(tempEnabled);
    }
}

  • 重写了Filter接口的init方法,用于在过滤器初始化时从过滤器配置中读取参数。
  • 通过filterConfig.getInitParameter("excludes")获取配置中的排除 URL 列表参数,如果该参数不为空,使用逗号分割字符串得到 URL 数组,然后遍历数组将每个 URL 添加到excludes列表中。
  • 通过filterConfig.getInitParameter("enabled")获取配置中的过滤开关参数,如果该参数不为空,将其转换为布尔值并设置给enabled变量。

四、过滤方法部分复制

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
    if (handleExcludeURL(req, resp)) {
        chain.doFilter(request, response);
        return;
    }
    XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
    chain.doFilter(xssRequest, response);
}

  • 重写了Filter接口的doFilter方法,这是过滤器的核心处理方法。
  • ServletRequestServletResponse强制转换为HttpServletRequestHttpServletResponse,以便进行 HTTP 特定的操作。
  • 调用handleExcludeURL方法判断当前请求的 URL 是否需要排除在 XSS 过滤之外。如果是,直接将原始请求传递给后续处理链并返回;如果不是,创建一个XssHttpServletRequestWrapper对象包装原始请求,对请求进行 XSS 过滤处理,然后将包装后的请求传递给后续处理链。

五、排除 URL 处理方法部分

private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
    if (!enabled) {
        return true;
    }
    if (excludes == null || excludes.isEmpty()) {
        return false;
    }
    String url = request.getServletPath();
    for (String pattern : excludes) {
        Pattern p = Pattern.compile("^" + pattern);
        Matcher m = p.matcher(url);
        if (m.find()) {
            return true;
        }
    }
    return false;
}

  • 定义了一个私有方法handleExcludeURL,用于判断当前请求的 URL 是否应该被排除在 XSS 过滤之外。
  • 如果 XSS 过滤开关enabledfalse,直接返回true,表示不进行过滤。
  • 如果排除列表excludesnull或者为空,返回false,表示不排除任何 URL。
  • 获取当前请求的 URL(通过request.getServletPath()),然后遍历排除列表中的每个模式。对于每个模式,使用正则表达式Pattern.compile("^" + pattern)进行编译,然后使用Matcher对象进行匹配。如果匹配成功,返回true,表示该 URL 需要排除在 XSS 过滤之外;如果没有任何 URL 匹配成功,返回false,表示该 URL 需要进行 XSS 过滤。

六、销毁方法部分

@Override
public void destroy() {

}
  • 重写了Filter接口的destroy方法,目前为空方法,可用于在过滤器被销毁时进行清理操作。

接着看 

com/ruoyi/common/xss/XssHttpServletRequestWrapper.java

package com.ruoyi.common.xss;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;

/**
 * XSS过滤处理
 * 
 * @author ruoyi
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
{
    /**
     * @param request
     */
    public XssHttpServletRequestWrapper(HttpServletRequest request)
    {
        super(request);
    }

    @Override
    public String[] getParameterValues(String name)
    {
        String[] values = super.getParameterValues(name);
        if (values != null)
        {
            int length = values.length;
            String[] escapseValues = new String[length];
            for (int i = 0; i < length; i++)
            {
                // 防xss攻击和过滤前后空格
                escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim();
            }
            return escapseValues;
        }
        return super.getParameterValues(name);
    }
}

以下是对这段代码的分析:

一、功能
提供对 HTTP 请求参数进行 XSS(跨站脚本攻击)过滤的功能。

二、主要功能

  1. 继承HttpServletRequestWrapper类,对请求进行包装,以便在不改变原始请求对象的情况下对请求参数进行处理。
  2. 重写getParameterValues方法,对请求参数进行 XSS 过滤和前后空格的去除。

三、代码逻辑

  1. 类定义和构造函数
    • public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper:定义一个名为XssHttpServletRequestWrapper的类,继承自HttpServletRequestWrapper
    • public XssHttpServletRequestWrapper(HttpServletRequest request):构造函数,接收一个HttpServletRequest对象,并将其传递给父类构造函数进行初始化。
  2. 重写getParameterValues方法
    • 首先调用父类的getParameterValues方法获取请求参数的值数组。
    • 如果参数值数组不为null,遍历数组中的每个值。
    • 对于每个值,使用Jsoup.clean(values[i], Whitelist.relaxed())进行 XSS 过滤,这里使用了Jsoup库的clean方法,并传入一个较为宽松的白名单(Whitelist.relaxed())。
    • 对过滤后的字符串进行前后空格的去除(.trim())。
    • 将处理后的参数值存储到新的数组中,并返回这个新数组。
    • 如果参数值数组为null,直接返回父类的getParameterValues方法的结果。

用途

在 Web 应用中,此代码可用于防止用户输入的恶意脚本被执行,从而提高应用的安全性。通常在 Servlet 过滤器中调用这个包装类来处理请求。例如,在一个防止 XSS 攻击的过滤器中,可以像这样使用这个包装类:

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.xss.XssHttpServletRequestWrapper;

public class XssFilter implements Filter {
    //...

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        // 使用 XssHttpServletRequestWrapper 包装原始请求
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(req);

        chain.doFilter(xssRequest, response);
    }

    //...
}

在上述示例中,XssFilter过滤器在处理请求时,使用XssHttpServletRequestWrapper对原始的HttpServletRequest进行包装,确保请求参数经过 XSS 过滤后再传递给后续的处理逻辑。这样,在整个 Web 应用的请求处理流程中,就可以有效地防止 XSS 攻击。

以下是对这段代码按代码块进行分析:

一、包声明和导入部分

package com.ruoyi.common.xss;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
  • 声明了包名com.ruoyi.common.xss
  • 导入了HttpServletRequestHttpServletRequestWrapper,用于对 HTTP 请求进行包装和扩展。
  • 导入了Jsoup库中的Jsoup类和Whitelist枚举,用于进行 XSS 过滤。

二、类定义部分

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    /**
     * @param request
     */
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

  • 定义了一个名为XssHttpServletRequestWrapper的类,继承自HttpServletRequestWrapper
  • 提供了一个构造函数,接收一个HttpServletRequest对象,并将其传递给父类的构造函数进行初始化。

三、重写getParameterValues方法部分

@Override
public String[] getParameterValues(String name) {
    String[] values = super.getParameterValues(name);
    if (values!= null) {
        int length = values.length;
        String[] escapseValues = new String[length];
        for (int i = 0; i < length; i++) {
            // 防xss攻击和过滤前后空格
            escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim();
        }
        return escapseValues;
    }
    return super.getParameterValues(name);
}
  • 重写了父类的getParameterValues方法,用于获取指定参数名的参数值数组。
  • 首先调用父类的方法获取参数值数组。
  • 如果参数值数组不为null,则进行以下处理:
    • 计算参数值数组的长度,并创建一个新的同长度的字符串数组escapseValues
    • 遍历参数值数组,对于每个值,使用Jsoup.clean(values[i], Whitelist.relaxed())进行 XSS 过滤,这里使用了Jsoup库的clean方法,并传入一个较为宽松的白名单(Whitelist.relaxed())。然后对过滤后的字符串进行前后空格的去除(.trim()),并将结果存储到新的数组中。
    • 最后返回处理后的新数组。
  • 如果参数值数组为null,则直接返回父类方法的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值