【问题标题】:Migrating away from Spring Security OAuth 2从 Spring Security OAuth 2 迁移
【发布时间】:2021-06-24 19:29:33
【问题描述】:

我有一个 Spring Boot Auth 微服务。它使用 Oauth2 spring cloud starter 依赖项 deprecated nowadays

buildscript {
  dependencies {
    classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.9.RELEASE"
  }
}

dependencies {
  implementation "org.springframework.boot:spring-boot-starter-actuator"
  implementation "org.springframework.boot:spring-boot-starter-data-jpa"
  implementation "org.springframework.boot:spring-boot-starter-web"
  implementation "org.springframework.cloud:spring-cloud-starter-oauth2:2.1.5.RELEASE"
}

架构取自这里:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql

它还有一个自定义的user_details 表。 JPA 类正在实现UserDetails。我还为UserDetailsService 提供了一个实现,它在我的自定义表中查找用户。

OAuth 配置相当前卫:

AuthorizationServerConfiguration - 配置 oauth 的位置:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableAuthorizationServer
class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() {
    @Autowired private lateinit var authenticationManager: AuthenticationManager
    @Autowired private lateinit var dataSource: DataSource

    @Autowired
    @Qualifier("customUserDetailsService")
    internal lateinit var userDetailsService: UserDetailsService

    @Autowired
    private lateinit var passwordEncoder: BCryptPasswordEncoder

    override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) {
        endpoints
                .tokenStore(JdbcTokenStore(dataSource))
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
    }

    override fun configure(clients: ClientDetailsServiceConfigurer) {
        // This one is used in conjunction with oauth_client_details. So like there's one app client and a few backend clients.
        clients.jdbc(dataSource)
    }

    override fun configure(oauthServer: AuthorizationServerSecurityConfigurer) {
        oauthServer.passwordEncoder(passwordEncoder)
    }
}

WebSecurityConfiguration - 上面的类需要:

@Configuration
class WebSecurityConfiguration : WebSecurityConfigurerAdapter() {
  @Bean // We need this as a Bean. Otherwise the entire OAuth service won't work.
  override fun authenticationManagerBean(): AuthenticationManager {
    return super.authenticationManagerBean()
  }

  override fun configure(http: HttpSecurity) {
    http.sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  }
}

ResourceServerConfiguration - 配置端点访问:

@Configuration
@EnableResourceServer
class ResourceServerConfiguration : ResourceServerConfigurerAdapter() {
  override fun configure(http: HttpSecurity) {
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and().cors().disable().csrf().disable()
        .authorizeRequests()

        .antMatchers("/oauth/token").authenticated()
        .antMatchers("/oauth/user/**").authenticated()

        .antMatchers("/oauth/custom_end_points/**").hasAuthority("my-authority")

        // Deny everything else.
        .anyRequest().denyAll()
  }
}

这几行给了我很多。

  • 用户信息端点(由微服务使用)
  • 移动前端等客户端可以使用以下方式进行身份验证:POST oauth/token 并提供 grant_type=password 以及用户名和密码。
  • 服务器可以使用 'oauth/authorize' 进行授权
  • 还可以使用不同权限的基本身份验证支持,因为我可以将用户名 + 密码填写到 oauth_client_details 表中:
select client_id, access_token_validity, authorities, authorized_grant_types, refresh_token_validity, scope from oauth_client_details;
     client_id     | access_token_validity |          authorities          |          authorized_grant_types           | refresh_token_validity |  scope
-------------------+-----------------------+-------------------------------+-------------------------------------------+------------------------+---------
 backend           |                864000 | mail,push,app-register        | mail,push,client_credentials              |                 864000 | backend
 app               |                864000 | grant                         | client_credentials,password,refresh_token |                      0 | app

如果还没有 oauth 令牌,应用程序会使用它。

其他微服务也使用它来保护它们的端点——例如在这个例子中:

@Configuration @EnableResourceServer class ResourceServerConfig : ResourceServerConfigurerAdapter() {
  override fun configure(http: HttpSecurity) {
    http.authorizeRequests()
        // Coach.
        .antMatchers("/api/my-api/**").hasRole("my-role")
        .antMatchers("/registration/**").hasAuthority("my-authority")
  }
}

他们的设置很简单:

security.oauth2.client.accessTokenUri=http://localhost:20200/oauth/token
security.oauth2.client.userAuthorizationUri=http://localhost:20200/oauth/authorize
security.oauth2.resource.userInfoUri=http://localhost:20200/oauth/user/me
security.oauth2.client.clientId=coach_client
security.oauth2.client.clientSecret=coach_client

前三个属性只是转到我的授权服务器。最后两个属性是我也插入到oauth_client_details 表中的实际用户名+密码。当我的微服务想要与它使用的另一个微服务通信时:

val details = ClientCredentialsResourceDetails()
details.clientId = "" // Values from the properties file.
details.clientSecret = "" // Values from the properties file.
details.accessTokenUri = "" // Values from the properties file.
val template = OAuth2RestTemplate(details)
template.exchange(...)

现在我的问题是 - 我怎样才能通过 Spring Security 的内置支持使用 Spring Boot 获得所有这些?我想从已弃用的软件包中迁移出来并保留所有令牌,以便用户在之后仍然登录。

【问题讨论】:

    标签: spring spring-boot oauth-2.0 oauth


    【解决方案1】:

    我们也在运行一个 spring 安全授权服务器并对此进行了调查。目前,spring 中的授权服务器组件没有替代品,而且似乎也没有时间表来实施。您最好的选择是查看现有的身份验证组件,例如 keycloak 或 nimbus。或者,也有像 okta 或 auth0 这样的托管服务。

    保留您现有的令牌将是一个挑战,因为您需要将它们导入到您的新解决方案中。我们当前的令牌是不透明的,而较新的身份验证解决方案倾向于使用某些版本的 jwt,因此根据您的令牌,保留它们甚至可能不是一种选择。

    现在我们考虑在一段时间内同时接受旧代币和新代币,直到旧代币的生存期结束,此时我们将完全迁移到新的基础设施。

    【讨论】:

    • 您有什么消息/您目前的工作情况如何?
    猜你喜欢
    • 1970-01-01
    • 2019-02-18
    • 1970-01-01
    • 2020-07-07
    • 2022-11-03
    • 1970-01-01
    • 2012-11-14
    • 2019-01-19
    • 2017-05-30
    相关资源
    最近更新 更多