【问题标题】:How to extract custom Principal in OAuth2 Resource Server?如何在 OAuth2 资源服务器中提取自定义主体?
【发布时间】:2020-08-02 18:15:44
【问题描述】:

我使用 Keycloak 作为我的 OAuth2 授权服务器,并按照GitHub 上的官方示例配置了一个用于多租户的 OAuth2 资源服务器。 考虑到 JWT 令牌的 Issuer 字段来解析当前租户。 因此,令牌会根据在相应 OpenID Connect 众所周知的端点上公开的 JWKS 进行验证。

这是我的安全配置:

@EnableWebSecurity
@RequiredArgsConstructor
@EnableAutoConfiguration(exclude = UserDetailsServiceAutoConfiguration.class)
public class OrganizationSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final TenantService tenantService;
    private List<Tenant> tenants;

    @PostConstruct
    public void init() {
        this.tenants = this.tenantService.findAllWithRelationships();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .oauth2ResourceServer()
                .authenticationManagerResolver(new MultiTenantAuthenticationManagerResolver(this.tenants));
    }
}

这是我的自定义 AuthenticationManagerResolver

public class MultiTenantAuthenticationManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> {

    private final AuthenticationManagerResolver<HttpServletRequest> resolver;

    private List<Tenant> tenants;

    public MultiTenantAuthenticationManagerResolver(List<Tenant> tenants) {
        this.tenants = tenants;

        List<String> trustedIssuers = this.tenants.stream()
                .map(Tenant::getIssuers)
                .flatMap(urls -> urls.stream().map(URL::toString))
                .collect(Collectors.toList());

        this.resolver = new JwtIssuerAuthenticationManagerResolver(trustedIssuers);
    }

    @Override
    public AuthenticationManager resolve(HttpServletRequest context) {
        return this.resolver.resolve(context);
    }
}

现在,因为org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver.TrustedIssuerJwtAuthenticationManagerResolver的设计 这是private,我想提取自定义主体的唯一方法是重新实现以下所有内容:

  • TrustedIssuerJwtAuthenticationManagerResolver
  • 返回的AuthenticationManager
  • 身份验证转换器
  • CustomAuthenticationToken 扩展了 JwtAuthenticationToken
  • CustomPrincipal

对我来说,似乎很多重新发明轮子,我唯一需要的是有一个自定义的 Principal。

我发现的示例似乎不适合我的情况,因为它们指的是 OAuth2Client 或者不适用于多租户。

我真的需要重新实现所有此类/接口,还是有更聪明的方法?

【问题讨论】:

  • 你有没有找到关于这件事的任何其他信息?
  • 遗憾的是什么都没有
  • 嗨,你解决了吗?能否提供更多信息?

标签: spring-boot spring-security spring-security-oauth2


【解决方案1】:

我就是这样做的,没有重新实现大量的类。然而,这没有使用 JwtAuthenticationToken。

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  ...

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    
    http
      ...
      .oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver()));
  }

  @Bean
  JwtIssuerAuthenticationManagerResolver authenticationManagerResolver() {

    List<String> issuers = ... // get this from list of tennants or config, whatever
    Predicate<String> trustedIssuer = issuers::contains;
    Map<String, AuthenticationManager> authenticationManagers = new ConcurrentHashMap<>();

    AuthenticationManagerResolver<String> resolver = (String issuer) -> {
      if (trustedIssuer.test(issuer)) {
        return authenticationManagers.computeIfAbsent(issuer, k -> {
          var jwtDecoder = JwtDecoders.fromIssuerLocation(issuer);
          var provider = new JwtAuthenticationProvider(jwtDecoder);
          provider.setJwtAuthenticationConverter(jwtAuthenticationService::loadUserByJwt);
          return provider::authenticate;
        });
      }
      return null;
    };
    
    return new JwtIssuerAuthenticationManagerResolver(resolver);
  }
}
@Service
public class JwtAuthenticationService {

  public AbstractAuthenticationToken loadUserByJwt(Jwt jwt) {
    
    UserDetails userDetails = ... // or your choice of principal
    List<GrantedAuthority> authorities = ... // extract from jwt or db
    ...
    return new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
  }
}

【讨论】:

    猜你喜欢
    • 2021-02-13
    • 2021-06-03
    • 2017-12-10
    • 2018-05-17
    • 2016-07-14
    • 2021-12-18
    • 2019-03-16
    • 2022-11-04
    • 2013-12-21
    相关资源
    最近更新 更多