资源服务器上的 Spring Boot OAuth2 自定义角色

Posted

技术标签:

【中文标题】资源服务器上的 Spring Boot OAuth2 自定义角色【英文标题】:Spring boot OAuth2 custom roles on Resource server 【发布时间】:2018-05-17 00:48:10 【问题描述】:

TL;DR:如何根据用户的 access_token 在资源服务器端(即没有 JWT)为用户分配自定义角色/权限?

整个故事:我有一个工作的 Auth 服务器和一个客户端(即 SPA),它可以从 Auth 服务器获取 access_token。使用该 access_token 客户端可以在我的资源服务器(与身份验证服务器分开)上请求数据。资源服务器可以使用 access_token 从 Auth 服务器获取用户名。

我可以通过将Authentication 对象注入这样的方法来访问代码中的用户名:

@RequestMapping("/ping")
fun pingPong(auth: Authentication): String = "pong, " + auth.name

我的问题是如何根据用户名将我的自定义角色或权限(auth.authorities - 只有 USER_ROLE)添加到将在资源服务器而不是身份验证服务器上管理的对象。

我已经尝试了几种方法来做到这一点,但都没有帮助。最有希望的是:

@Configuration
@EnableWebSecurity
@EnableResourceServer
class ResourceServerConfigurer(val userDetailsService: MyUserDetailsService) : ResourceServerConfigurerAdapter() 

    override fun configure(http: HttpSecurity) 
        http.userDetailsService(userDetailsService) // userDetailsService is autowired
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeRequests()
                .antMatchers("/", "/index.html").permitAll()
                .anyRequest().authenticated()
    

还有我的自定义 UserDetailsS​​ervice:

@Service
class UserDetailsService : org.springframework.security.core.userdetails.UserDetailsService 

    override fun loadUserByUsername(username: String): UserDetails 
        return org.springframework.security.core.userdetails.User(username, "password", getAuthorities(username))

    

    private fun getAuthorities(user: String): Set<GrantedAuthority> 
        val authorities = HashSet<GrantedAuthority>()
        authorities.addAll(listOf(
                SimpleGrantedAuthority("ROLE_ONE"),  //let's grant some roles to everyone
                SimpleGrantedAuthority("ROLE_TWO")))
        return authorities
    

一切正常(我的意思是我已成功通过身份验证),但我仍然只有 ROLE_USER。接下来我尝试的是提供 AbstractUserDetailsAuthenticationProvider 的自定义实现:

@Bean
fun authenticationProvider(): AbstractUserDetailsAuthenticationProvider 
    return object : AbstractUserDetailsAuthenticationProvider() 
        override fun retrieveUser(username: String, authentication: UsernamePasswordAuthenticationToken): UserDetails 
            return User(username, "password", getAuthorities(username))

        

        private fun getAuthorities(user: String): Set<GrantedAuthority> 
            val authorities = HashSet<GrantedAuthority>()
            authorities.addAll(listOf(
                    SimpleGrantedAuthority("ROLE_ONE"),
                    SimpleGrantedAuthority("ROLE_TWO")))
            return authorities
        

        override fun additionalAuthenticationChecks(userDetails: UserDetails, authentication: UsernamePasswordAuthenticationToken?) 
        
    

结果相同,只有 ROLE_USER 存在。

我真的很感谢你们在验证 access_token 并从 Auth 服务器获取用户名之后如何向 Authentication 对象添加一些角色的任何想法。

【问题讨论】:

我已将您的解决方案移至社区 wiki 答案。 【参考方案1】:

OP 的解决方案。

首先我需要提供自定义的PrincipalExtractorAuthoritiesExtractor 实现。但是要让 Spring 使用它们,配置中必须不要使用 security.oauth2.resource.token-info-uri,而是使用 security.oauth2.resource.user-info-uri(我真的没想到这是我问题的根源之一)。 最后,安全配置必须在ResourceServerConfigurerAdapter 中完成,而不是在WebSecurityConfigurerAdapter 中。

最终代码如下所示:

    @SpringBootApplication
    @RestController
    class MyApplication 
    
        @RequestMapping("/ping")
        fun pingPong(user: Authentication): String 
            return "pong, " + user.name + " - " + user.authorities.joinToString()
        
    
    
    @Configuration
    @EnableWebSecurity
    @EnableResourceServer
    class ResourceServerConfigurer : ResourceServerConfigurerAdapter() 
    
        override fun configure(http: HttpSecurity) 
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and().authorizeRequests()
                    .antMatchers("/", "/index.html").permitAll()
                    .anyRequest().authenticated()
        
    
        @Bean
        fun principalExtractor() = PrincipalExtractor 
            return@PrincipalExtractor it["name"]
        
    
        @Bean
        fun authoritiesExtractor() = AuthoritiesExtractor 
            return@AuthoritiesExtractor AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ONE,ROLE_TWO")
        
    
    
    fun main(args: Array<String>) 
        SpringApplication.run(MyApplication::class.java, *args)
    

【讨论】:

以上是关于资源服务器上的 Spring Boot OAuth2 自定义角色的主要内容,如果未能解决你的问题,请参考以下文章

使用Spring boot的OAuth2认证服务器和资源服务器

Spring Boot OAuth 资源服务器代理配置

spring-boot oauth2 拆分授权服务器和资源服务器

Spring Boot - 使用 JWT、OAuth 以及单独的资源和身份验证服务器

独立资源服务器(Spring Boot 2 + OAuth + JWT)在 Spring-boot 从 1.2.x 升级到 2.x 后给出 UsernameNotFoundException

Spring Boot OAuth 2.0 客户端