如何将 ResourceServer 添加到现有的 spring 安全配置

Posted

技术标签:

【中文标题】如何将 ResourceServer 添加到现有的 spring 安全配置【英文标题】:How to add a ResourceServer to an existing spring security config 【发布时间】:2020-03-12 13:17:14 【问题描述】:

我使用以下安全配置进行授权。我现在想向这个项目添加令牌安全端点。

但是,每当我向安全端点发送请求时,我总是会发现自己被重定向到登录页面 ("/oauth_login"),就好像我未经授权一样。 我在这里做错了什么?我尝试对此进行调试,当我尝试使用有效令牌访问端点时,似乎从未调用过我的 accessTokenConverter 的覆盖 decode() 函数。

这是我已有的安全配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PropertySource("application.properties")
@Order(1)
class SecurityConfig(
        private val userDetailsService: CustomUserDetailsService,
        private val inMemoryClientRegistrationRepository: InMemoryClientRegistrationRepository,
        private val secretAuthenticationFilter: SecretAuthenticationFilter
) : WebSecurityConfigurerAdapter() 

    @Bean
    @Throws(Exception::class)
    override fun authenticationManager() = super.authenticationManager()

    @Throws(Exception::class)
    override fun configure(auth: AuthenticationManagerBuilder?) 
        auth!!.userDetailsService(userDetailsService)
                .passwordEncoder(BCryptPasswordEncoder(10))
    

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) 
               .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

        http.addFilterAfter(secretAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)

        http
                .authorizeRequests()
                .antMatchers("/oauth_login")
                .permitAll()
                .antMatchers("/accounts/password")
                .permitAll()
                .anyRequest()
                .authenticated()
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logoutconfirm")
                .logoutSuccessUrl("/oauth_login")
                .invalidateHttpSession(true)
                .and()
                .oauth2Login().loginPage("/oauth_login")
                .authorizationEndpoint()
                .baseUri("/oauth2/authorize-client")
                .authorizationRequestRepository(authorizationRequestRepository())
                .authorizationRequestResolver(CustomAuthorizationRequestResolver(inMemoryClientRegistrationRepository, "/oauth2/authorize-client"))
                .and()
                .tokenEndpoint()
                .accessTokenResponseClient(accessTokenResponseClient())
                .and()
                .defaultSuccessUrl("/loginSuccess")
                .failureUrl("/loginFailure")
                .addObjectPostProcessor(object : ObjectPostProcessor<Any> 
                    override fun <O : Any> postProcess(obj: O) = when (obj) 
                        is OAuth2LoginAuthenticationProvider -> CustomOAuth2LoginAuthenticationProvider(obj) as O
                        is LoginUrlAuthenticationEntryPoint -> customizeLoginUrlAuthenticationEntryPoint(obj) as O
                        else -> obj
                    
                )

    

这是我要添加的 ResourceServerConfig:

@Configuration
@EnableResourceServer
@Order(2)
class ResourceServerConfig(
        private val defaultTokenServices: DefaultTokenServices
) : ResourceServerConfigurerAdapter() 

    override fun configure(config: ResourceServerSecurityConfigurer) 
        config.tokenServices(tokenServices())
    

    override fun configure(http: HttpSecurity) 
        http.authorizeRequests().anyRequest().authenticated()

    

    fun tokenStore() = JwtTokenStore(accessTokenConverter())

    fun accessTokenConverter(): JwtAccessTokenConverter 
        val converter = object : JwtAccessTokenConverter() 
            override fun decode(token: String) = if (token.isCorrectJwtToken(token)) 
                super.decode(token)
             else 
                mapOf()
            
        

        val keyStoreKeyFactory = KeyStoreKeyFactory(ClassPathResource("mykeys.jks"),
                "mykeys".toCharArray())
        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mykeys"))
        return converter
    

    fun tokenServices() = DefaultTokenServices().apply 
        setTokenStore(tokenStore())
        setSupportRefreshToken(true)
    

这是我希望能够使用有效令牌访问的安全端点:

    @PreAuthorize("hasAuthority('ROLE_USER')")
    @PostMapping("/accounts/password")
    fun updatePassword(@RequestBody newPassword: JsonWrappedValue<String>): Boolean 
        // Update password
    

【问题讨论】:

【参考方案1】:

我找到了解决问题的方法。 我将所有配置合并到一个文件中,因此安全配置看起来像这样

@EnableAuthorizationServer
@EnableResourceServer
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PropertySource("application.properties")
class SecurityConfig(
        private val accountRepository: AccountRepository,
        private val userDetailsService: CustomUserDetailsService,
        private val inMemoryClientRegistrationRepository: InMemoryClientRegistrationRepository,
        private val secretAuthenticationFilter: SecretAuthenticationFilter
) : AuthorizationServerConfigurer, ResourceServerConfigurer, WebSecurityConfigurerAdapter() 

这使我最终能够使用令牌到达我的端点,但破坏了我的社交登录。 然后我必须修复 configure(http: HttpSecurity) 方法,因为 ResourceServerConfig 的默认实现将 SessionCreationPolicy 设置为 SessionCreationPolicy.Never

这导致我的社交登录被破坏,因为包含redirectUri等的请求参数无法恢复。添加后

http.sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)

configure(http: HTTPSecurity) 完整配置运行良好。

【讨论】:

以上是关于如何将 ResourceServer 添加到现有的 spring 安全配置的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Mailchimp 添加到现有的注册框

如何将新行添加到现有的 QTablewidget

如何将熊猫数据添加到现有的 csv 文件中?

如何将文件添加到现有的 docker 镜像? [复制]

如何将自定义 UIViewController 添加到现有的 XIB?

如何将 JPA 添加到现有的 Eclipse 项目?