Spring Security注册过滤器注意事项详解

 更新时间:2024年06月04日 08:22:33   作者:江南一点雨  
前两天和小伙伴聊了 Spring Security+JWT 实现无状态登录,然后有小伙伴反馈了一个问题,感觉这是一个我们平时写代码容易忽略的问题,所以本文给大家介绍了Spring Security注册过滤器注意事项,需要的朋友可以参考下

一 问题复原

先来说问题吧,在 Spring Security+JWT 登录中,整体上的思路就是用户登录成功之后返回 JWT 字符串,然后以后用户每次请求都携带上 JWT 字符串,服务端进行校验,校验通过之后,请求继续执行。

按照上面的思路,我们的项目中需要有一个 JwtFilter 用来从请求中提取请求传来的 Jwt 字符串进行校验,类似下面这样:

@Component
public class JwtFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        String requestURI = req.getRequestURI();
        if ("/login".equals(requestURI)) {
            //登录请求,无需校验令牌,请求继续执行
            filterChain.doFilter(xxx,xxx);
            return;
        }
        //令牌校验
    }
}

然后有一个小伙伴反馈,在项目中使用了 WebSecurityCustomizer 给 Swagger 相关的请求都放行了,结果这些被放行的请求都被 JwtFilter 拦截了,这是咋回事呢?

首先小伙伴们要知道,使用 WebSecurityCustomizer 放行的请求,都不再经过 SecurityFilter 了,所以按理不该再被 JwtFilter 拦截了,因为 JwtFilter 是隶属于 SecurityFilter 这个过滤器链中的,并非原生的跟 Servlet 平级的那种 Filter。

但是为什么又拦截了呢?

松哥看了下代码,发现问题出在 @Component 这个注解上。

二 原理分析

在 Spring Boot 项目启动的时候,有一个环节就是把 Spring 容器中所有类型为 Filter 的 Bean 找出来,并且自动添加到容器的过滤器链条中(注意不是添加到 Spring Security 过滤器链中)。

这段代码的逻辑位于 ServletContextInitializerBeans#addAdaptableBeans 方法中,在该方法中,会调用 addAsRegistrationBean 方法完成以上事情:

private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
		Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
	List<Map.Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);
	for (Entry<String, B> entry : entries) {
		String beanName = entry.getKey();
		B bean = entry.getValue();
		if (this.seen.add(bean)) {
			// One that we haven't already seen
			RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
			int order = getOrder(bean);
			registration.setOrder(order);
			this.initializers.add(type, registration);
		}
	}
}

可以看到,这里传入的参数 type 和 beanType 都是 Filter,从 Spring 容器中找到 Filter 类型的 Bean 存入到 initializers 集合中。不过注意,添加到集合中的实际上是封装之后的 registration 对象,这个对象通过 adapter.createRegistrationBean 方法创建出来,在该方法中,由于我们没有为当前过滤器设置拦截的请求地址,所以默认拦截所有请求,拦截规则是 /*

最后在 ServletWebServerApplicationContext#selfInitialize 方法中遍历上一步找到的过滤器,并逐个进行配置,相关代码如下:

DynamicRegistrationBean#register:

@Override
protected final void register(String description, ServletContext servletContext) {
    //注册过滤器
	D registration = addRegistration(description, servletContext);
	//省略
}

AbstractFilterRegistrationBean#addRegistration:

@Override
protected Dynamic addRegistration(String description, ServletContext servletContext) {
	Filter filter = getFilter();
	return servletContext.addFilter(getOrDeduceName(filter), filter);
}

可以看到,这最终就是大家熟知的添加过滤器的代码了。

三 解决方案

找到问题的原因,那么问题就好解决了。

问题的产生,主要是因为 Spring 自动查找容器中所有 Filter 类型的 Bean,并进行配置,那么我们的解决方案就是不要把这个 Bean 注册到 Spring 容器中,即不要添加 @Component 注解,而是直接自己 new 出来就行了,在配置过滤器链的时候,像下面这样配置即可:

http.addFilterAfter(new JwtFilter(redisTemplate), SecurityContextHolderFilter.class);

经过上面这样配置之后,JwtFilter 就不存在于原生过滤器链中了,只是单纯的存在于 SecurityFilter 中。

理解了 Spring Security 原理,那么日常开发中各种奇奇怪怪的情况,我们就都能轻车熟路的解决了。

到此这篇关于Spring Security注册过滤器注意事项详解的文章就介绍到这了,更多相关Spring Security注册过滤器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot整合SSE技术开发小结

    springboot整合SSE技术开发小结

    本文主要介绍了springboot整合SSE技术开发小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-11-11
  • Intellij Idea修改代码方法参数自动提示快捷键的操作

    Intellij Idea修改代码方法参数自动提示快捷键的操作

    这篇文章主要介绍了Intellij Idea修改代码方法参数自动提示快捷键的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • SpringBoot使用Sa-Token实现权限认证

    SpringBoot使用Sa-Token实现权限认证

    本文主要介绍了SpringBoot使用Sa-Token实现权限认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • java反射机制根据属性名获取属性值的操作

    java反射机制根据属性名获取属性值的操作

    这篇文章主要介绍了java反射机制根据属性名获取属性值的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • java匿名内部类实例简析

    java匿名内部类实例简析

    匿名类是不能有名称的类,所以没办法引用它们,必须在创建时,作为new语句的一部分来声明它们,需要了解更多的可以参考本文
    2012-11-11
  • JavaWeb表单注册界面的实现方法

    JavaWeb表单注册界面的实现方法

    这篇文章主要介绍了JavaWeb表单注册界面的实现方法的相关资料,希望通过本文大家能掌握这部分内容,需要的朋友可以参考下
    2017-09-09
  • SpringBoot整合阿里云视频点播的过程详解

    SpringBoot整合阿里云视频点播的过程详解

    视频点播(ApsaraVideo for VoD)是集音视频采集、编辑、上传、自动化转码处理、媒体资源管理、分发加速于一体的一站式音视频点播解决方案。这篇文章主要介绍了SpringBoot整合阿里云视频点播的详细过程,需要的朋友可以参考下
    2021-12-12
  • java HashMap通过value反查key的代码示例

    java HashMap通过value反查key的代码示例

    本文讲解了java HashMap通过value反查key的方法,直接提供代码供大家参考使用
    2013-11-11
  • Spring中@Autowired注解作用在方法上和属性上说明

    Spring中@Autowired注解作用在方法上和属性上说明

    这篇文章主要介绍了Spring中@Autowired注解作用在方法上和属性上说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • springboot使用shiro-整合redis作为缓存的操作

    springboot使用shiro-整合redis作为缓存的操作

    这篇文章主要介绍了springboot使用shiro-整合redis作为缓存的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06

最新评论