首页>>后端>>Spring->解决Spring AOP 在RememberMeServices 导致的NullPointerException

解决Spring AOP 在RememberMeServices 导致的NullPointerException

时间:2023-11-29 本站 点击:0

原因分析

原因是 AbstractRememberMeServices 有一个被外部调用的final方法,cglib无法代理final方法导致的,而这个方法又使用了this+类变量,而生成cglib代理类不会初始化类变量,所以直接报 NullPointerException

@OverridepublicfinalvoidloginSuccess(HttpServletRequestrequest,HttpServletResponseresponse,AuthenticationsuccessfulAuthentication){if(!rememberMeRequested(request,this.parameter)){this.logger.debug("Remember-meloginnotrequested.");return;}onLoginSuccess(request,response,successfulAuthentication);}

解决办法

解决办法是添加一个init()方法,通过反射获取类变量并赋值

publicclassLogRememberMeServicesextendsPersistentTokenBasedRememberMeServices{@AutowiredprivateLogRememberMeServicesmySelf;publicLogRememberMeServices(Stringkey,UserDetailsServiceuserDetailsService,PersistentTokenRepositorytokenRepository){super(key,userDetailsService,tokenRepository);}/***填充cglib代理的一些字段,弥补cglib代理类不能代理{@linkAbstractRememberMeServices#loginSuccess}方法和{@linkAbstractRememberMeServices#autoLogin}方法导致的缺陷*/publicfinalvoidinit()throwsNoSuchFieldException,IllegalAccessException{checkAndSet("parameter",getParameter());checkAndSet("logger",LogFactory.getLog(AbstractRememberMeServices.class));checkAndSet("userDetailsChecker",newAccountStatusUserDetailsChecker());}privatevoidcheckAndSet(StringfieldName,Objectvalue)throwsIllegalAccessException,NoSuchFieldException{Fieldfield=AbstractRememberMeServices.class.getDeclaredField(fieldName);field.setAccessible(true);if(field.get(this)==null){field.set(this,value);}}@OverrideprotectedUserDetailsprocessAutoLoginCookie(String[]cookieTokens,HttpServletRequestrequest,HttpServletResponseresponse){returnmySelf.AutoLoginCookie(cookieTokens,request,response);}/***自定义AOP注解实现登录日志*/@Logging(value=LoginLog.class)publicUserDetailsAutoLoginCookie(String[]cookieTokens,HttpServletRequestrequest,HttpServletResponseresponse)throwsAuthenticationException{returnsuper.processAutoLoginCookie(cookieTokens,request,response);}}

然后在手动执行一次init()方法即可

@BeanpublicLogRememberMeServicesrememberMeServices(UserDetailsServiceuserDetailsService,PersistentTokenRepositorypersistentTokenRepository){LogRememberMeServicesrememberMeServices=newLogRememberMeServices(REMEMBER_ME_KEY,userDetailsService,persistentTokenRepository);rememberMeServices.setTokenValiditySeconds(60*60*24*30);returnrememberMeServices;}@BeanSecurityFilterChaindefaultSecurityFilterChain(HttpSecurityhttp,LoginLimitServiceloginLimitService,CaptchaServicecaptchaService,RememberMeServicesrememberMeServices,SocialServicesocialService,AuthenticationFailureHandlerauthenticationFailureHandler)throwsException{//填充cglib代理的一些字段,弥补cglib代理类不能代理{@linkAbstractRememberMeServices#loginSuccess}方法导致的缺陷if(rememberMeServicesinstanceofLogRememberMeServices){((LogRememberMeServices)rememberMeServices).init();}returnhttp.authorizeRequests(authorizeRequests->authorizeRequests.antMatchers("/login/**").permitAll().anyRequest().authenticated()).rememberMe().key(REMEMBER_ME_KEY).rememberMeServices(rememberMeServices).and().cors().and().csrf(t->t.ignoringAntMatchers("/captcha/**")).formLogin(Customizer.withDefaults()).logout(Customizer.withDefaults()).headers().frameOptions().disable().and().build();}

参考链接:

廖雪峰:AOP避坑指南AbstractRemembermeService logger为null导致登录失败透过现象看原理:详解Spring中Bean的this调用导致AOP失效的原因揭秘 Spring AOP 失效的罪因,看了都说好!Spring AOP出现NullPointerException


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/340.html