繁体   English   中英

如何配置 Spring Boot 以使用 AWS Cognito (OAuth2/OIDC) 对 Web 应用程序用户和 REST 客户端进行身份验证

[英]How to configure Spring Boot to authenticate Web-app users and REST clients using AWS Cognito (OAuth2/OIDC)

我需要配置 Spring 引导服务器以使用 AWS Cognito 用户池对 Web 用户和 REST 客户端进行身份验证:

  1. 使用 ReachJS 前端的交互式/Web 用户应重定向到 Cognito 进行身份验证,并在验证用户凭据后重定向回来。
  2. 直接使用服务器的 REST API 的其他机器应该从 Cognito 获取令牌并将其作为Authorization: Bearer... header。

问题是:

  1. 如何配置 spring 以使用 Cognito 进行身份验证
  2. 你如何让 spring 同时支持这两种不同类型的身份验证

概述

让我们从术语开始:

  1. IDP(身份提供者)是提供用户管理和身份验证服务的第 3 方,在我的例子中是 AWS Cognito。
  2. 通过将交互式/Web 用户重定向到 IDP 来对其进行身份验证在 OAuth2/OIDC 中称为“授权代码授予流程”。
  3. 客户端将 JWT 令牌发送到 REST API 被称为“客户端凭证流”。

Spring 的spring-security-oauth2-client模块负责“授权码授予流程”, spring-security-oauth2-resource-server模块负责“客户端凭证流程”。

为了同时使用这两种流程/方法,我们需要告诉 spring 如何确定对传入的 HTTP 请求使用哪种身份验证方法。 正如https://stackoverflow.com/a/64752665/2692895中所解释的,这可以通过查找Authorization: bearer... header 来完成:

  1. 如果请求包含Authorization header,则假定其为 REST 客户端并使用“客户端凭据流”。
  2. 否则,它是一个交互式用户,如果尚未经过身份验证,则重定向到 Cognito。

依赖关系

我正在使用 Spring-Boot 2.6.6(Spring 5.6.2)。

        <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>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
        </dependency>

外部配置 - application.yaml

spring:
  security:
    oauth2:
      # Interactive/web users authentication
      client:
        registration:
          cognito:
            clientId: ${COGNITO_CLIENT_ID}
            clientSecret: ${COGNITO_CLIENT_SECRET}
            scope: openid
            clientName: ${CLIENT_APP_NAME}
        provider:
          cognito:
            issuerUri: https://cognito-idp.eu-central-1.amazonaws.com/${COGNITO_POOL_ID}
            user-name-attribute: email

      # REST API authentication
      resourceserver:
        jwt:
          issuer-uri: https://cognito-idp.eu-central-1.amazonaws.com/${COGNITO_POOL_ID}

Spring 安全配置

交互式/网络用户身份验证:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
    // Needed for method access control via the @Secured annotation
    prePostEnabled = true,
    jsr250Enabled = true,
    securedEnabled = true
)
@Profile({"cognito"})
@Order(2)
public class CognitoSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @SneakyThrows
    @Override
    protected void configure(HttpSecurity http) {
        http
            // TODO disable CSRF because when enabled controllers aren't initialized
            //  and if they are, POST are getting 403
            .csrf().disable()

            .authorizeRequests()
            .anyRequest().authenticated()

            .and()
            .oauth2Client()

            .and()
            .logout()

            .and()
            .oauth2Login()
            .redirectionEndpoint().baseUri("/login/oauth2/code/cognito")
            .and()
        ;
    }
}

REST 客户端认证:

/**
 * Allow users to use a token (id-token, jwt) instead of the interactive login.
 * The token is specified as the "Authorization: Bearer ..." header.
 * </p>
 * To get a token, the cognito client-app needs to support USER_PASSWORD_AUTH then use the following command:
 * <pre>
 *     aws cognito-idp initiate-auth --auth-flow USER_PASSWORD_AUTH --output json \
 *         --region $region --client-id $clientid --auth-parameters "USERNAME=$username,PASSWORD=$password" \
 *         | jq .AuthenticationResult.IdToken
 * </pre>
 */
@Slf4j
@Configuration
@Profile({"cognito"})
@Order(1)
public class CognitoTokenBasedSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @SneakyThrows
    @Override
    protected void configure(HttpSecurity http) {
        http
            .requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
            .authorizeRequests().anyRequest().authenticated()
            .and().oauth2ResourceServer().jwt()
        ;
    }

}

Cognito 配置说明

  • 在 AWS Cognito 中,您需要创建一个用户池和两个客户端应用程序,一个用于交互式/网络用户的“公共客户端”和一个用于基于令牌的 REST 客户端的“机密客户端”。
  • 在“公共客户端”中,确保为所有环境(本地主机、生产环境等)定义“允许的回调 URL”,它们都应类似于 http://localhost:8080/login/oauth2/code/cognito (当然是使用正确的主机名和端口)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM