Spring Security Kotlin中Repository类字段注入失败问题排查
问题根源
你在SecurityConfig里犯了一个关键错误:虽然通过构造函数注入了Spring容器管理的AuthenticationSuccessHandler实例,但在配置OAuth2登录的successHandler时,你手动新建了一个未被Spring管理的AuthenticationSuccessHandler()对象。这个手动创建的对象不在Spring的容器生命周期里,Spring不会为它注入userRepository,所以调用时就会触发lateinit未初始化的异常。
另外,你的AuthenticationSuccessHandler使用@Autowired标注lateinit属性的方式虽然可行,但Kotlin里更推荐用构造函数注入,能从根源避免这类未初始化问题。
修复步骤
1. 修正SecurityConfig的配置
把successHandler(AuthenticationSuccessHandler())改成直接使用构造函数注入的实例:
@EnableWebSecurity @Configuration class SecurityConfig(private val authenticationSuccessHandler: AuthenticationSuccessHandler) { @Throws(Exception::class) @Bean fun override(http: HttpSecurity): SecurityFilterChain { return http .csrf { csrf -> csrf.disable() } .authorizeRequests { auth -> auth.antMatchers("/api/brackets").authenticated() auth.antMatchers("/**").permitAll() } .oauth2Login() .successHandler(authenticationSuccessHandler) // 这里用注入的实例,不要新建 .and() .build() } }
2. 优化AuthenticationSuccessHandler的注入方式(可选但推荐)
把@Autowired的lateinit属性改成构造函数注入,这样Spring会在创建实例时直接注入userRepository,彻底避免未初始化问题:
@Component class AuthenticationSuccessHandler( private val userRepository: UserRepository // 构造函数注入 ) : SavedRequestAwareAuthenticationSuccessHandler() { private val redirectStrategy: RedirectStrategy = DefaultRedirectStrategy() private val logger: Logger = LoggerFactory.getLogger(javaClass) @Throws(ServletException::class, IOException::class) override fun onAuthenticationSuccess(request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication) { val requestCache: RequestCache = HttpSessionRequestCache() val savedRequest: SavedRequest? = requestCache.getRequest(request, response) // 处理可能的null返回 val userDetails: DefaultOidcUser = authentication.principal as DefaultOidcUser logger.info(userDetails.idToken.tokenValue) userRepository.save(User(userDetails.name, userDetails.email, AuthService.GOOGLE)) redirectStrategy.sendRedirect(request, response, "/api/testAuth") } }
注意:原代码里
requestCache.getRequest(request, response)可能返回null,所以变量类型要改成SavedRequest?,避免空指针异常。
补充说明
- Spring只会对自己容器管理的Bean进行依赖注入,手动
new出来的对象不属于容器,所以不会自动注入依赖。 - Kotlin的构造函数注入是更安全的方式,能在编译期就检查依赖是否存在,而
lateinit属性是运行期检查,容易出现未初始化的问题。
内容的提问来源于stack exchange,提问作者Ethan Michel
相关产品推荐
相关产品推荐

