簡體   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