如何在 Filter 中调用服务层

问题产生的背景

集成spring-secrity时,需求是希望在jwt Filter中调用UserService以及自定义的UserDetailService,当通过注解**@Resource**注入,报方法为 null

问题产生原因

web应用启动的顺序是:listener->filter->servlet

拦截器加载的时间点在 springcontext 之前,所以在拦截器中注入自然为 null

解决方法

//拦截器调用服务层
ServletContext context = request.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
UserService userService = ctx.getBean(UserService.class);
MyUserDetailServiceImpl myUserDetailService = ctx.getBean(MyUserDetailServiceImpl.class);

spring-security 5.7.1 新版本配置

版本迭代导致部分类被移除

在Spring Security的5.7.x版本下,WebSecurityConfigurerAdapter类已经被废弃,后续版本将被移除,所以更新POM后WebSecurityConfigurerAdapter有弃用告警(已被标记@Deprecated),但依旧可以使用。
升级前

类似代码

  • SecurityConfig 类继承WebSecurityConfigurerAdapter
  • 需要重写Adapter中的三个方法进行配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.antMatcher("/**")
.authorizeRequests(authorize -> authorize
.anyRequest().authenticated()
);
}
}
升级后
  • 通过@Bean方式注入
  • 不再继承WebSecurityConfigurerAdapter,只需直接声明配置类,再配置一个生成SecurityFilterChainBean的方法,把原来的HttpSecurity配置移动到该方法中
  • 自定义的方法同样通过@Bean注入

类似代码

@Configuration
public class SecurityConfig {

@Bean
SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
//省略HttpSecurity的配置
httpSecurity.
...//省略
.formLogin()
.usernameParameter("userAccount")//自定义 Security自带的login方法中的username参数为userAccount
.passwordParameter("userPassword")//自定义Security自带的login方法中的password参数为userPassword
...//省略
//JWT自定义过滤器
.addFilter(new JwtAuthenticationFilter(authenticationManager));
return httpSecurity.build();
}


}

/**
*
* 创建BCryptPasswordEncoder注入Spring容器
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}

/**
* 获取AuthenticationManager(认证管理器),登录时认证使用
* @param authenticationConfiguration
* @return
* @throws Exception
*/
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

spring-security 前端适配自带的 login 方法

  • spring-security 默认有一个登录方法,前端需要适配一下, 我前端登录页已经开发完成,所以修改的security配置,将默认的usernamepassword自定义和前端一样,默认请求的 url 为/login
  • 前端的请求方式需要改变,由原先的json改成form提交
import qs from 'qs' ....//s export function loginRequest(loginParam: IAccount) {
return hyRequest.post({ url: '/api/login', data: qs.stringify(loginParam),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
httpSecurity.
...//省略
.formLogin()
.usernameParameter("userAccount")//自定义 Security自带的login方法中的username参数为userAccount
.passwordParameter("userPassword")//自定义Security自带的login方法中的password参数为userPassword