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

  • 相关阅读:
    多策略黑猩猩优化算法-附代码
    超算,先进计算未来的研究方向有哪些?
    关于电影的HTML网页设计-威海影视网站首页-电影主题HTM5网页设计作业成品
    Vue 最简单路由 页面路由 配置路由
    什么是右值引用,跟左值又有什么区别
    网络安全(黑客)自学
    JAVA的参数传递方式
    工程水文学名词解释总结
    Mysql优化---数据库引擎
    解决因对EFCore执行SQL方法不熟练而引起的问题
  • 原文地址:https://blog.csdn.net/ybb_ymm/article/details/125604160