今天被人提了个问题——在过滤器(Filter)中注入Bean后拿不到对象(为null),如何避免这个坑?
废话不多说了,咱们直接看解决方案代码吧!
首先来看一下过滤器中的内容:
认证过滤器配置了,获取用户输入用户名和密码方法,认证成功方法及认证失败处理方法,以及日志入库封装代码;
当认证成功后,记录日志入库的时候,会发现此处的journalService是null,无法获取相对应的Bean对象,
java复制代码
/**
* 认证过滤器
*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private Logger logger = LoggerFactory.getLogger(TokenLoginFilter.class);
private TokenManager tokenManager;
private JournalService journalService;
private RedisTemplate redisTemplate;
// 权限管理工具,由SpringSecurity封装提供
private AuthenticationManager authenticationManager;
public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate,JournalService journalService) {
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
this.journalService = journalService;
this.setPostOnly(false);
}
// 1 获取表单提交用户名和密码
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
//获取表单提交数据
try {
User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword(),
new ArrayList<>()));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
// 2 认证成功调用的方法
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
insertJournal(user,request);
ResponseUtil.out(response, apiResult);
}
// 3 认证失败调用的方法
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
logger.info("认证登录失败,失败原因:{}",failed.getMessage());
ApiResult apiResult = new ApiResult();
apiResult.setResultCode(ApiResponse.FAIL.getResCode());
apiResult.setMsg("用户名密码错误");
ResponseUtil.out(response, apiResult);
}
@Async
public void insertJournal(SecurityUser user,HttpServletRequest request) throws BaseException {
Journal journal = new Journal();
journal.setCreateTime(new Date());
journal.setMethod("login");
journal.setName(user.getUsername());
journal.setIpAddress(IpUtils.getIp(request));
journal.setRemark("登录成功");
journalService.insertSelective(journal);
}
}
通过上面的代码便是拦截其中注入Bean的操作,此时如果没有任何配置,则注入的Bean全部获取不到对象值,全部为null
接下来我们看解决方案:
次配置类中公共构造函数中会按照系统注入所需要的tokenManager、redisTemplate、defaultPasswordEncoder、userDetailsService、journalServiced对象。
相对应的配置设置会实现商法所说的注入动作,这样即可完成正确的Bean注入操作
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
private DefaultPasswordEncoder defaultPasswordEncoder;
private UserDetailsService userDetailsService;
private JournalService journalService;
@Autowired
public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,
TokenManager tokenManager, RedisTemplate redisTemplate,JournalService journalService) {
this.userDetailsService = userDetailsService;
this.defaultPasswordEncoder = defaultPasswordEncoder;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
this.journalService = journalService;
}
/**
* 配置设置
* @param http
* @throws Exception
*/
// 设置退出的地址和token,redis操作地址
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.exceptionHandling()
.authenticationEntryPoint(new UnauthEntryPoint()) // 没有权限访问
.and().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated() //任何请求,登录后可以访问
.and().logout().logoutUrl("/index/logout")//退出路径
.addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
.addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate,journalService))
.addFilter(new TokenAuthFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
}
}
这一步中的关键便是构造函数中为注入Bean赋值,然后配置Filter时注入对象即可。
好了,这样即可完成过滤器中注入Bean操作,觉得有帮助,帮小编点个赞吧!