带有 Spring Security 的 Amazon Cognito Oauth2

Posted

技术标签:

【中文标题】带有 Spring Security 的 Amazon Cognito Oauth2【英文标题】:Amazon Cognito Oauth2 with Spring Security 【发布时间】:2018-06-27 21:13:10 【问题描述】:

我正在尝试使用“Cognito Oauth2”在资源服务器中实现 Spring Security,但是我似乎没有找到太多信息。关于它(或者如果它甚至可能这样做)。

我最近的方法是使用“Nimbus+JOSE”通过“JWKS”检查“访问令牌”的有效性,并授予访问资源的权限。 (类似于他们在此处找到的“API 网关资源保护实施”示例:https://aws.amazon.com/es/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/)

【问题讨论】:

【参考方案1】:

Baeldung 网站上有一个具体示例说明如何执行此操作

https://www.baeldung.com/spring-security-oauth-cognito

【讨论】:

【参考方案2】:

我们可以创建 Spring Boot 资源服务器,保持 Cognito 作为身份提供者。

依赖:

    <!--  Spring Security-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security.oauth.boot</groupId>
        <artifactId>spring-security-oauth2-autoconfigure</artifactId>
        <version>2.0.1.RELEASE</version>
    </dependency>

Spring 安全配置:

EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerSecurityConfiguration extends ResourceServerConfigurerAdapter 

  private final ResourceServerProperties resource;

  public OAuth2ResourceServerSecurityConfiguration(ResourceServerProperties resource) 
    this.resource = resource;
  

  @Override
  public void configure(HttpSecurity http) throws Exception 

    http.cors();

    http.csrf().disable();

    http.authorizeRequests()
        .antMatchers("/api/public/**").permitAll()
        .antMatchers("/actuator/health").permitAll()
        .anyRequest().authenticated();
  


  // Note: Cognito Converter
  @Bean
  public TokenStore jwkTokenStore() 
    return new JwkTokenStore(
        Collections.singletonList(resource.getJwk().getKeySetUri()),
        new CognitoAccessTokenConverter(),
        null);
  

Cognito 访问令牌转换器:

在这里,我们将 Cognito 声明转换为 Spring Security 可消费格式。

@Component
public class CognitoAccessTokenConverter extends JwtAccessTokenConverter 

  // Note: This the core part.
  private static final String COGNITO_GROUPS = "cognito:groups";
  private static final String SPRING_AUTHORITIES = "authorities";
  private static final String COGNITO_USERNAME = "username";
  private static final String SPRING_USER_NAME = "user_name";

  @SuppressWarnings("unchecked")
  @Override
  public OAuth2Authentication extractAuthentication(Map<String, ?> claims) 

    if (claims.containsKey(COGNITO_GROUPS))
      ((Map<String, Object>) claims).put(SPRING_AUTHORITIES, claims.get(COGNITO_GROUPS));
    if (claims.containsKey(COGNITO_USERNAME))
      ((Map<String, Object>) claims).put(SPRING_USER_NAME, claims.get(COGNITO_USERNAME));
    return super.extractAuthentication(claims);
  

application.properties

server:
  port: 8081
security:
  oauth2:
    resource:
      userInfoUri: https://<cognito>.auth.eu-west-1.amazoncognito.com/oauth2/userInfo
      tokenInfoUri: https://<cognito>.auth.eu-west-1.amazoncognito.com/oauth2/token
      jwk:
        key-set-uri: https://cognito-idp.<region>.amazonaws.com/<user-pool-id>/.well-known/jwks.json
    client:
      clientId: <client-id>

完整文章请参考:Integrate Spring Boot Resource Server with Cognito Identity Provider

【讨论】:

我喜欢这个解决方案,但 ResourceServerProperties 在春季已被弃用... 如今,REST API 通常通过具有 Cognito 集成的 API-Gateway 托管。 有趣,虽然我计划使用 API-GW,但我并没有考虑过这个选项。会看那个。但是,不能解决已弃用的问题:) @Louis-wht,您能否分享任何参考链接,说明此弃用。我看到 spring-boot-starter-oauth2-resource-server 已在 2020 年 1 月推出了最新版本。 这个答案的核心是指出CognitoAccessTokenConverter,它将Cognito claims转换为spring-security格式。我认为,在迁移之后,您可能仍需要相同的解决方案来进行 cognito 集成。【参考方案3】:

可以在这里找到使用最新 Sprint Boot 2.x / Sprint Security 5.x 的 Oauth2 的一个很好的起点:https://spring.io/blog/2018/03/06/using-spring-security-5-to-integrate-with-oauth-2-secured-services-such-as-facebook-and-github

它使用 Facebook / Github 作为示例,但您也可以将其应用于 AWS Cognito。

这是迄今为止使用 Spring Security / Cognito OAuth2 设置安全 REST 后端的最简单方法。您的后端将通过 Spring Security 得到保护,AWS Cognito 将用作身份提供者。

您可以使用文章中概述的 spring security starter 设置一个 vanilla spring boot 应用程序,并使用以下依赖项:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-jose</artifactId>
    </dependency>

并像这样提供您的 cognito 配置(客户端注册 + 提供者定义):

spring:
  security:
    oauth2:
      client:
        registration:
          cognito-client-1:
            client-id: 391uhnjlr8v8kicm3cru6g1s8g
            client-secret: xxxxxxxxxxxxxxxxxxxxxxxxxx
            client-name: Cognito Code Grant
            provider: cognito
            scope: openid
            redirect-uri-template: http://localhost:8080/login/oauth2/code/cognito
            authorization-grant-type: authorization_code
        provider:
          cognito:
            authorization-uri: https://custom-domain.auth.eu-central-1.amazoncognito.com/oauth2/authorize
            token-uri: https://custom-domain.auth.eu-central-1.amazoncognito.com/oauth2/token
            user-info-uri: https://custom-domain.auth.eu-central-1.amazoncognito.com/oauth2/userInfo
            jwk-set-uri: https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxxxxxxx/.well-known/jwks.json
            user-name-attribute: cognito:username

就 Cognito 而言,您需要在 cognito 中拥有一个包含几个用户的用户池/身份池和一个有效的应用客户端(= client-id in spring config)

一个秘密(= client-secret 在 spring 配置中) 正确的授权和范围(在这种情况下,我使用的是带有 openid 范围的授权代码授权) 正确的重定向回调(= redirect-uri-template 在 spring 配置中) cognito 中的域配置 包含您的 cognito 用户池的 JWK uri(spring 配置中的jwk-set-uri

一切就绪后,Spring Boot 应用会自动生成登录 url

将您重定向到 cognito 登录页面,您可以在其中输入您的 cognito 凭据

在成功验证后,您将能够进行安全的 REST 调用

使用这样的 REST 控制器:

@RestController
public class ExampleController 

    @RequestMapping("/")
    public String email(Principal principal) 
        return "Hello " + principal.getName();
    


【讨论】:

我也在努力创造这些东西,却不知道这一切都是在春天处理的。至于对我帮助最大的 Cognito 资源是:github.com/aws-quickstart/saas-identity-cognito 您如何管理注销?我有弹簧在注销后自动登录,所以用户不会被注销 试图解决同样的问题 Kappa。看看这个:docs.aws.amazon.com/pt_br/cognito/latest/developerguide/… @AlexandreMucci 感谢您的提示,我已经阅读了注销端点文档,但是在使 HTTP 会话无效并删除 cookie 之前注销时,spring security 似乎没有调用此类端点;所以我的用户实际上并没有被注销。此外,对我来说似乎很奇怪的是,在下一个请求中没有 cookie、没有本地存储数据和没有其他标头参数会自动让我再次登录(但只能从同一个浏览器的同一个选项卡) @smac2020 你完成了吗?如果是的话,你能分享一下官方文档吗?

以上是关于带有 Spring Security 的 Amazon Cognito Oauth2的主要内容,如果未能解决你的问题,请参考以下文章

带有 OpenIDAuthenticationFilter 问题的 Spring Security

带有 spring-boot 和 spring-security 的 JWT

带有 Spring Security 的 Spring REST 不接受凭据

带有 LDAP 注销的 Spring Security 无法删除会话

如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?

我们如何使用带有 Spring 5.0 的最新 spring-security-oauth2 jar 来实现授权服务器?