今天被人提了个问题——在拦截器(Filter)中注入Bean后拿不到对象(为null),如何避免这个坑?
废话不多说了,咱们直接看解决方案代码吧!
首先来看一下拦截器中的内容:
认证拦截其中配置了,获取用户输入用户名和密码方法,认证成功方法及认证失败处理方法,以及日志入库封装代码;
当认证成功后,记录日志入库的时候,会发现此处的journalService是null,无法获取相对应的Bean对象,
/** * 认证过滤器 */ 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操作,觉得有帮助,帮小编点个赞吧!
更多编程内容,请扫码关注《coder练习生》,如果觉得有用,也可赠送作者一杯咖啡