• 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练习生》,如果觉得有用,也可赠送作者一杯咖啡

  • 相关阅读:
    量子计算实现:量子算法的实现
    零基础学习OSI七层网络模型
    web 性能提升(将持续更新……)
    追寻红色记忆、晋国文明之思考毕业季研学营
    贝锐蒲公英智慧运维方案:实现远程网络监控、管理、维护工业设备
    nginx日志进行统计分析 log分析
    什么是java的流程控制语句,java又有哪些流程控制语句
    【GIT版本控制管理】第4章 基本的Git概念
    使用了百度OCR,记录一下
    FPGA 学习笔记:IP Clocking Wizard 的基本操作
  • 原文地址:https://blog.csdn.net/ybb_ymm/article/details/125604160