

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 傳入聯合 Lambda 觸發
<a name="user-pool-lambda-inbound-federation"></a>

傳入聯合觸發會在使用外部身分提供者的身分驗證程序期間轉換聯合身分使用者屬性。當使用者透過設定的身分提供者進行身分驗證時，此觸發可讓您透過攔截和轉換身分驗證程序中的資料來修改外部 SAML 和 OIDC 提供者的回應，以程式設計方式控制 Amazon Cognito 使用者集區如何處理聯合身分使用者及其屬性。

在建立新使用者或更新現有的聯合身分使用者設定檔之前，使用此觸發條件來新增、覆寫或隱藏屬性。此觸發會接收原始身分提供者屬性做為輸入，並傳回 Amazon Cognito 套用至使用者設定檔的修改屬性。

**Topics**
+ [流程概觀](#cognito-user-pools-lambda-trigger-inbound-federation-flow)
+ [傳入聯合 Lambda 觸發參數](#cognito-user-pools-lambda-trigger-syntax-inbound-federation)
+ [傳入聯合範例：群組成員資格管理](#aws-lambda-triggers-inbound-federation-example-groups)
+ [傳入聯合範例：截斷大型屬性](#aws-lambda-triggers-inbound-federation-example-truncate)
+ [傳入聯合範例：記錄聯合事件](#aws-lambda-triggers-inbound-federation-example-logging)

## 流程概觀
<a name="cognito-user-pools-lambda-trigger-inbound-federation-flow"></a>

當使用者向外部身分提供者進行身分驗證時，Amazon Cognito 會在建立或更新使用者設定檔之前叫用傳入聯合觸發條件。觸發程序會從身分提供者接收原始屬性，並在 Amazon Cognito 存放它們之前進行轉換。新聯合身分使用者和透過聯合再次登入的現有使用者都會發生此流程。

![\[傳入聯合 Lambda 觸發流程\]](http://docs.aws.amazon.com/zh_tw/cognito/latest/developerguide/images/lambda-inbound-federation.png)


## 傳入聯合 Lambda 觸發參數
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation"></a>

Amazon Cognito 傳遞至此 Lambda 函數的請求，是以下參數和 Amazon Cognito 新增至所有請求的[常用參數](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared)之組合。

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": AWSRegion,
    "userPoolId": "string",
    "userName": "string",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "string",
        "providerType": "string",
        "attributes": {
            "tokenResponse": {
                "access_token": "string",
                "token_type": "string",
                "expires_in": "string"
            },
            "idToken": {
                "sub": "string",
                "email": "string",
                "email_verified": "string"
            },
            "userInfo": {
                "email": "string",
                "given_name": "string",
                "family_name": "string"
            },
            "samlResponse": {
                "string": "string"
            }
        }
    },
    "response": {
        "userAttributesToMap": {
            "string": "string"
        }
    }
}
```

------

### 傳入聯合請求參數
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation-request"></a>

**providerName**  
外部身分提供者的名稱。

**providerType**  
外部身分提供者的類型。有效值：`OIDC`、`SAML`、`Facebook`、`Google`、`SignInWithApple`、`LoginWithAmazon`。

**屬性**  
處理之前從身分提供者收到的原始屬性。結構會根據提供者類型而有所不同。

**attributes.tokenResponse**  
來自`/token`端點的 OAuth 字符回應資料。僅適用於 OIDC 和社交供應商。包含 `access_token`、`id_token`、`refresh_token`、`expires_in`、 `token_type`和 `scope`。

**attributes.idToken**  
解碼和驗證的 ID 字符 JWT 宣告。僅適用於 OIDC 和社交供應商。包含已驗證的使用者身分資訊，包括 `sub`（唯一的使用者識別符）`email`、、`name`、 `iss` （發行者）、 `aud` （對象）、 `exp`（過期） 和 `iat`（發行時間）。

**attributes.userInfo**  
來自 UserInfo 端點的延伸使用者設定檔資訊。僅適用於 OIDC 和社交供應商。包含詳細的設定檔屬性，例如 `given_name`、`family_name`、`address`、 `picture`和其他提供者特定欄位。如果 IdP 不支援 UserInfo 端點或端點呼叫失敗，則可能是空的。

**attributes.samlResponse**  
SAML 聲明屬性。僅適用於 SAML 供應商。包含來自 SAML 回應的屬性。

### 傳入聯合回應參數
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation-response"></a>

**userAttributesToMap**  
要套用至使用者設定檔的使用者屬性。

**重要**  
您必須在回應中包含要保留的所有使用者屬性，包括您未修改的屬性。`userAttributesToMap` 回應中未包含的任何屬性都會遭到捨棄，不會存放在使用者設定檔中。這同時適用於已修改和未修改的屬性。

**空的回應行為**  
如果您傳回 `{}`的空物件`userAttributesToMap`，身分提供者的所有原始屬性都會保持不變。這可做為無操作，就像從未執行 Lambda 函數一樣。這與省略屬性不同，這會捨棄它們。

**提供者特定的屬性**  
的結構會根據 `request.attributes`而有所不同`providerType`。OIDC 和社交提供者包括 `tokenResponse`、 `idToken`和 `userInfo` 物件。SAML 供應商僅包含 `samlResponse` 物件。

## 傳入聯合範例：群組成員資格管理
<a name="aws-lambda-triggers-inbound-federation-example-groups"></a>

此範例說明如何將聯合身分提供者群組映射至 Amazon Cognito 使用者集區群組。此函數會從聯合回應中擷取群組成員資格，並自動將使用者新增至對應的 Amazon Cognito 群組，無需進行身分驗證後觸發。

------
#### [ Node.js ]

```
exports.handler = async (event) => {
    const { providerType, attributes } = event.request;
    
    // Extract user attributes based on provider type
    let userAttributesFromIdp = {};
    if (providerType === 'SAML') {
        userAttributesFromIdp = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        userAttributesFromIdp = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    // Extract groups from federated response
    const federatedGroups = userAttributesFromIdp.groups?.split(',') || [];
    
    // Map federated groups to Cognito groups
    const groupMapping = {
        'Domain Admins': 'Administrators',
        'Engineering': 'Developers',
        'Sales': 'SalesTeam'
    };
    
    // Filter to only in-scope groups
    const mappedGroups = federatedGroups
        .map(group => groupMapping[group.trim()])
        .filter(group => group); // Remove undefined values
    
    // Pass through attributes with mapped groups as custom attribute
    const attributesToMap = {
        ...userAttributesFromIdp,
        'custom:user_groups': mappedGroups.join(',')
    };
    
    // Remove original groups attribute
    delete attributesToMap.groups;
    
    event.response.userAttributesToMap = attributesToMap;
    return event;
};
```

------

Amazon Cognito 會將事件資訊傳遞至您的 Lambda 函數。此函數會將相同事件物件傳回 Amazon Cognito，並在回應中附上任何變更。在 Lambda 主控台中，您可使用與 Lambda 觸發程序相關聯的資料來設定測試事件。下列是此程式碼範例的測試事件：

------
#### [ JSON ]

```
{
    "userPoolId": "us-east-1_XXXXXXXXX",
    "request": {
        "providerName": "CorporateAD",
        "providerType": "SAML",
        "attributes": {
            "samlResponse": {
                "email": "jane.smith@company.com",
                "given_name": "Jane",
                "family_name": "Smith",
                "groups": "Engineering,Domain Admins",
                "department": "Engineering"
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

## 傳入聯合範例：截斷大型屬性
<a name="aws-lambda-triggers-inbound-federation-example-truncate"></a>

此範例示範如何截斷超過 Amazon Cognito 儲存限制的屬性值。此函數會檢查身分提供者的每個屬性。如果屬性值超過 2048 個字元，則會截斷該值並新增省略號來表示截斷。所有其他屬性都會傳遞不變。

------
#### [ Node.js ]

```
exports.handler = async (event) => {
    const MAX_ATTRIBUTE_LENGTH = 2048;
    
    // Get the identity provider attributes based on provider type
    const { providerType, attributes } = event.request;
    let idpAttributes = {};
    
    if (providerType === 'SAML') {
        idpAttributes = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        idpAttributes = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    const userAttributes = {};
    
    // Process each attribute
    for (const [key, value] of Object.entries(idpAttributes)) {
        if (typeof value === 'string' && value.length > MAX_ATTRIBUTE_LENGTH) {
            // Truncate the value and add ellipsis
            userAttributes[key] = value.substring(0, MAX_ATTRIBUTE_LENGTH - 3) + '...';
            console.log(`Truncated attribute ${key} from ${value.length} to ${userAttributes[key].length} characters`);
        } else {
            // Keep the original value
            userAttributes[key] = value;
        }
    }
    
    // Return the modified attributes
    event.response.userAttributesToMap = userAttributes;
    return event;
};
```

------

Amazon Cognito 會將事件資訊傳遞至您的 Lambda 函數。此函數會將相同事件物件傳回 Amazon Cognito，並在回應中附上任何變更。在 Lambda 主控台中，您可使用與 Lambda 觸發程序相關聯的資料來設定測試事件。下列是此程式碼範例的測試事件：

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": "us-east-1",
    "userPoolId": "us-east-1_XXXXXXXXX",
    "userName": "ExampleProvider_12345",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "ExampleProvider",
        "providerType": "OIDC",
        "attributes": {
            "tokenResponse": {
                "access_token": "abcDE...",
                "token_type": "Bearer",
                "expires_in": "3600"
            },
            "idToken": {
                "sub": "12345",
                "email": "user@example.com"
            },
            "userInfo": {
                "email": "user@example.com",
                "given_name": "Example",
                "family_name": "User",
                "bio": "This is a very long biography that contains more than 2048 characters..."
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

## 傳入聯合範例：記錄聯合事件
<a name="aws-lambda-triggers-inbound-federation-example-logging"></a>

此範例說明如何記錄用於監控和偵錯的聯合身分驗證事件。此範例函數會擷取聯合身分使用者及其屬性的詳細資訊，以提供身分驗證程序的可見性。

------
#### [ Node.js ]

```
exports.handler = async (event) => {
    const { providerName, providerType, attributes } = event.request;
    
    // Extract user attributes based on provider type
    let userAttributesFromIdp = {};
    if (providerType === 'SAML') {
        userAttributesFromIdp = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        userAttributesFromIdp = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    // Log federated authentication details
    console.log(JSON.stringify({
        timestamp: new Date().toISOString(),
        providerName,
        providerType,
        userEmail: userAttributesFromIdp.email,
        attributeCount: Object.keys(userAttributesFromIdp).length,
        attributes: userAttributesFromIdp
    }));
    
    // Pass through all attributes unchanged
    event.response.userAttributesToMap = userAttributesFromIdp;
    return event;
};
```

------

Amazon Cognito 會將事件資訊傳遞至您的 Lambda 函數。此函數會將相同事件物件傳回 Amazon Cognito，並在回應中附上任何變更。在 Lambda 主控台中，您可使用與 Lambda 觸發程序相關聯的資料來設定測試事件。下列是此程式碼範例的測試事件：

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": "us-east-1",
    "userPoolId": "us-east-1_XXXXXXXXX",
    "userName": "CorporateAD_john.doe",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "CorporateAD",
        "providerType": "SAML",
        "attributes": {
            "samlResponse": {
                "email": "john.doe@company.com",
                "given_name": "John",
                "family_name": "Doe",
                "department": "Engineering",
                "employee_id": "EMP12345"
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

預期的 CloudWatch Logs 輸出：

------
#### [ JSON ]

```
{
    "timestamp": "2025-01-14T21:17:40.153Z",
    "providerName": "CorporateAD",
    "providerType": "SAML",
    "userEmail": "john.doe@company.com",
    "attributeCount": 5,
    "attributes": {
        "email": "john.doe@company.com",
        "given_name": "John",
        "family_name": "Doe",
        "department": "Engineering",
        "employee_id": "EMP12345"
    }
}
```

------