自定义范围_spring security授权服务器中支持

ojsjcaue  于 2023-03-02  发布在  Spring
关注(0)|答案(1)|浏览(144)

我对spring oauth服务器进行了以下配置

@Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());   // Enable OpenID Connect 1.0
        http
                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .authenticationEntryPoint(
                                new LoginUrlAuthenticationEntryPoint("/login"))
                )

                // Accept access tokens for User Info and/or Client Registration
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);

        return http.build();
    }

使用此已知配置(http://[host]/.well-known/openid-configuration),端点仅为scopes_supported提供openid
有没有办法自定义返回["openid", "email", "profile"]
scopes_supported在OidcProviderConfiguration端点筛选器中硬编码

bvuwiixz

bvuwiixz1#

我不确定这是否可以开箱即用。如果我没记错的话,Spring安全团队正在努力在Spring Security Authz Server的未来版本中启用更多OpenId连接特定功能。我不确定他们是否会开箱即用(或者)我们必须自己完成。
由于email只是一个作用域,我们可以在authz服务器级别为特定客户机注册这个作用域,也可以在客户端注册。
设置好后,需要做的是定制/userinfo端点。由于/userinfo在Spring Authz服务器上是安全的,即只能使用访问令牌访问(一旦authz代码流完成,Spring登录客户端会自动访问),我们需要定制它,以便可以在此端点上发送登录资源所有者的电子邮件详细信息。
可以用这种方式来完成。

@Component
class UserInfoResponseCustomizer implements Function<OidcUserInfoAuthenticationContext, OidcUserInfo> {
  private final UserDetailsService userDetailsService;

  public UserInfoResponseCustomizer(UserDetailsService userDetailsService) {
    this.userDetailsService = userDetailsService;
  }

  @Override
  public OidcUserInfo apply(OidcUserInfoAuthenticationContext oidcUserInfoAuthenticationContext) {
    final var authToken = ((JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication());
    final var resourceOwnerUsername = authToken.getName();
    final var builder = OidcUserInfo.builder().subject(resourceOwnerUsername);
    if (authToken.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("SCOPE_email"))) {
      final var userWithEmail = (UserWithEmail) userDetailsService.loadUserByUsername(resourceOwnerUsername);
      builder.email(userWithEmail.getEmail()); //UserWithEmail is a custom spring `UserDetails` object that contains email property
    }
    return builder.build();
  }
}

并将其连接到Authz服务器

@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, UserInfoResponseCustomizer userInfoResponseCustomizer) throws Exception {
  OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
  http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
      .oidc(customizer -> customizer.userInfoEndpoint(oidcUserInfoEndpointConfigurer -> oidcUserInfoEndpointConfigurer.userInfoMapper(userInfoResponseCustomizer)));    // Enable OpenID Connect 1.0

  http
      // Redirect to the login page when not authenticated from the
      // authorization endpoint
      .exceptionHandling((exceptions) -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
      // Accept access tokens for User Info and/or Client Registration
      .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);

  return http.build();
}

注册客户端时,请确保允许客户端请求该email作用域

@Bean
public RegisteredClientRepository registeredClientRepository() {
  RegisteredClient frontendClient = RegisteredClient.withId(UUID.randomUUID().toString())
      .clientId("my-client")
      .clientSecret("{noop}my-client-secret")
      .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
      .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
      .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
      .redirectUri("http://my-client.com/login/oauth2/code/my-client")
      .scope(OidcScopes.OPENID)
      .scope(OidcScopes.PROFILE)
      .scope(OidcScopes.EMAIL)
      .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
      .build();
}

在Authz服务器端进行这些更改后,您应该能够完成Auth代码流,并在Authz服务器上点击/userinfo端点,访问用户的电子邮件地址。
请注意,在spring登录模块中使用默认设置时,当客户端完成openid流的authz code流时,库会自动获取/userinfo端点,因此,您应该能够通过访问此对象(OidcUser)((OAuth2LoginAuthenticationToken)SecurityContextHolder.getContext().getAuthentication())).getPrincipal())中的声明,在oauth客户端访问此电子邮件地址。

相关问题