首页 文章

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

提问于
浏览
4

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

The whole story: 我有一个工作的Auth服务器和一个客户端(SPA),它可以从Auth服务器获取access_token . 使用该access_token,客户端可以在我的资源服务器(与Auth服务器分开)上请求数据 . 资源服务器可以使用access_token从Auth服务器获取用户名 .

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

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

我的问题是如何将此自定义角色或权限( auth.authorities - 只有USER_ROLE)添加到此对象,该对象将根据用户名在资源服务器而非Auth服务器上进行管理 .

我尝试了几种方法,但没有人帮助过 . 最有希望的是:

@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()
    }
}

我的自定义UserDetailsService:

@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对象添加一些角色 .

1 回答

  • 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)
    }
    

相关问题