Springboot过滤器中注入Bean

今天被人提了个问题——在过滤器(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练习生》,如果觉得有用,也可赠送作者一杯咖啡

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ybb_ymm

你的鼓励会是对我最大的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值