精通 Salesforce Named Credentials:安全 API 集成的综合指南

背景与应用场景

作为一名 Salesforce 集成工程师,我的日常工作核心就是连接 Salesforce 与外部世界。无论是将会计数据同步到 ERP 系统,从第三方服务获取实时物流信息,还是与市场营销自动化平台交换客户数据,API 集成都是这一切的基石。然而,在这些集成的背后,一个永恒的挑战始终存在:如何安全、高效地管理认证凭据 (Authentication Credentials)?

在早期,将 API 密钥 (API Keys)、用户名和密码等敏感信息硬编码在 Apex 代码中,或者存储在自定义设置 (Custom Settings) / 自定义元数据 (Custom Metadata) 中是一种常见但极其危险的做法。这种方式存在诸多弊病:

  • 安全风险:敏感凭据以明文或易于解码的形式存储,一旦代码或元数据泄露,将导致严重的安全漏洞。
  • 维护噩梦:当外部系统的密码或 API 密钥过期时,我们需要修改代码或元数据,然后经过完整的测试和部署周期,这既耗时又容易出错。如果在多个地方使用了相同的凭据,更新过程将更加复杂。
  • 环境管理困难:在 Sandbox 和生产环境 (Production) 之间,通常需要连接到外部系统的不同实例(例如,测试环境 vs. 生产环境)。管理这些不同环境的凭据和端点 URL 会变得非常混乱。

为了解决这些痛点,Salesforce 提供了 Named Credentials(命名凭据)这一强大且优雅的解决方案。它将端点 URL 和认证信息从代码中分离出来,由平台统一进行安全管理。这使得集成工程师可以专注于业务逻辑的实现,而将复杂的认证握手和凭据管理交给 Salesforce 平台处理。

典型的应用场景包括:

  • 连接 REST/SOAP API:调用外部服务,如 Google Maps API、Stripe 支付网关或任何企业内部的微服务。
  • 简化 Apex Callouts:在 Apex 代码中发起 HTTP 请求时,无需手动构建 `Authorization` 头部或处理 OAuth 2.0 的令牌刷新逻辑。
  • 赋能低代码工具:让 Flow(流)和 External Services(外部服务)等声明式工具也能安全地调用外部 API。
  • 支持不同认证协议:轻松处理 Basic Authentication、OAuth 2.0、JWT 等多种行业标准认证协议。

原理说明

要理解 Named Credentials 的工作原理,我们需要了解其核心组件。自 Winter '23 版本以来,Salesforce 对其架构进行了现代化升级,引入了 External Credentials (外部凭据)Principals (主体) 的概念,使得整个体系更加模块化和灵活。现在的 Named Credential 实际上是指向一个 External Credential 的一个“别名”或“快捷方式”。

1. External Credential (外部凭据)

这是认证配置的核心。它定义了“如何认证”,但并不包含特定用户的凭据。一个 External Credential 主要包含以下信息:

  • Authentication Protocol (认证协议): 定义了与外部系统通信时使用的认证类型。常见的选项包括:
    • OAuth 2.0: 适用于支持 OAuth 2.0 协议的服务,例如 Google, Microsoft, 或其他现代 API。Salesforce 会自动处理 Access Token (访问令牌) 的获取和刷新,极大地简化了开发。
    • Password Authentication: 对应于 HTTP Basic Auth,需要提供用户名和密码。
    • JWT Bearer Flow: 使用 JSON Web Token (JWT) 进行服务器到服务器的认证。
    • AWS Signature Version 4: 专用于连接 Amazon Web Services (AWS) 的 API。
    • Custom: 允许你通过 Apex 代码来自定义认证流程,提供了极高的灵活性。
  • Parameters (参数): 根据所选的协议,需要配置不同的参数。例如,对于 OAuth 2.0,你需要提供 `Client ID`、`Client Secret`、`Scope`、`Authorization URL` 和 `Token URL`。

External Credential 的设计理念是“一次定义,多处使用”。你可以创建一个代表公司内部 ERP 系统的 OAuth 2.0 认证配置,然后在多个 Named Credentials 中复用它。

2. Principal (主体)

Principal 定义了“谁在认证”。它将一个用户、一个权限集 (Permission Set) 或一个 Profile (简档) 与一个 External Credential 关联起来,并提供了实际的凭据信息。这实现了两种主要的认证模式:

  • Named Principal (指定主体): 这是系统对系统的集成模式。你为整个组织定义一个固定的凭据(例如,一个专用的集成用户的用户名和密码)。所有通过该 Named Credential 发起的 callout 都使用这个共享的凭据。
  • Per User (每用户): 这是用户上下文的集成模式。每个需要访问外部系统的 Salesforce 用户都需要在个人设置中单独授权。当该用户触发 callout 时,Salesforce 会使用该用户自己的凭-据。这对于需要代表特定用户在外部系统中执行操作的场景(例如,“以 John 的 Google 账户身份发布日历事件”)至关重要。

3. Named Credential (命名凭据)

Named Credential 现在扮演着一个“端点链接”的角色。它将一个具体的 URL 端点与一个配置好的 External Credential 绑定在一起。其主要包含:

  • URL: 外部服务的根 URL。例如 `https://api.example.com`。
  • Link to External Credential: 关联一个之前创建好的 External Credential。
  • Callout Options: 提供一些高级选项,如是否允许在 HTTP 头部或请求体中使用合并字段。

当你在 Apex 代码中使用 `callout:My_Named_Credential_Name/some/path` 这样的特殊 URL 格式时,Salesforce 会在幕后完成以下所有工作:

  1. 解析 `My_Named_Credential_Name`,找到关联的 Named Credential 和 External Credential。
  2. 根据 Principal 的配置,获取正确的认证凭据(是共享的系统凭据还是当前用户的凭据)。
  3. 执行所选认证协议的流程。如果是 OAuth 2.0,它会检查 Access Token 是否有效,如果过期,会自动执行 Refresh Token 流程以获取新的 Access Token。
  4. 将获取到的认证信息(例如,`Authorization: Bearer `)自动添加到 HTTP 请求的头部。
  5. 将请求发送到最终的 URL (`https://api.example.com/some/path`)。

整个过程对开发者完全透明。我们只需要提供一个简单的 `callout:` URL,剩下的复杂工作全部由平台搞定。


示例代码

以下是一个使用 Named Credential 发起 Apex HTTP Callout 的标准示例。假设我们已经创建了一个名为 `My_API_Service` 的 Named Credential,它指向 `https://api.example.com` 并配置了适当的认证。

此代码示例直接改编自 Salesforce 官方的 Apex Developer Guide,确保了其准确性和最佳实践。

// Apex Class to make a callout using a Named Credential
public class NamedCredentialCallout {
    
    public static String performGetCallout() {
        // 1. 创建一个 HttpRequest 对象
        // Create a new HttpRequest object.
        HttpRequest req = new HttpRequest();
        
        // 2. 设置请求方法为 GET
        // Set the HTTP method to GET.
        req.setMethod('GET');
        
        // 3. 设置端点。这是 Named Credential 的核心用法。
        // 'callout:' 前缀告诉 Salesforce 使用 Named Credential 机制。
        // 'My_API_Service' 是我们预先配置好的 Named Credential 的 API 名称。
        // '/api/v1/data' 是相对于 Named Credential 中定义的根 URL 的具体路径。
        // Salesforce 会自动将它拼接成完整的 URL:https://api.example.com/api/v1/data
        // 同时,Salesforce 会自动处理认证,将 token 或其他凭据添加到请求头中。
        // Set the endpoint using the 'callout:' syntax for a Named Credential.
        // Salesforce automatically appends the path to the URL defined in the Named Credential
        // and handles all authentication.
        req.setEndpoint('callout:My_API_Service/api/v1/data');
        
        // 4. (可选) 设置请求头。认证头由 Salesforce 自动添加,这里可以添加其他自定义头。
        // (Optional) Set any custom headers. The Authorization header is added automatically.
        req.setHeader('Content-Type', 'application/json');

        // 5. 创建一个 Http 对象来发送请求
        // Create a new Http object to send the request.
        Http http = new Http();
        
        String responseBody = '';

        try {
            // 6. 发送请求并获取 HttpResponse 对象
            // Send the request and get the response.
            HttpResponse res = http.send(req);
            
            // 7. 检查响应状态码并处理响应体
            // Check the status code and process the response body.
            if (res.getStatusCode() == 200) {
                responseBody = res.getBody();
                System.debug('Successful response: ' + responseBody);
            } else {
                responseBody = 'Error: Received status code ' + res.getStatusCode() + ' with message: ' + res.getStatus();
                System.debug(responseBody);
            }
        } catch(System.CalloutException e) {
            // 8. 捕获并处理 Callout 异常,例如 DNS 问题或超时。
            // Catch and handle any callout exceptions, such as network issues.
            responseBody = 'Callout error: ' + e.getMessage();
            System.debug(responseBody);
        }
        
        return responseBody;
    }
}

正如你所看到的,代码中完全没有任何关于用户名、密码、API 密钥或 Access Token 的痕迹。它干净、可读,并且与具体的认证细节完全解耦。


注意事项

  • 权限 (Permissions):
    • 创建和修改 Named Credentials、External Credentials 需要 “Customize Application” 权限。
    • 对于使用“每用户 (Per User)”认证的场景,用户需要被授予对 `External Credential Principal` 的访问权限(通常通过权限集),并且需要用户本人在个人设置中完成一次性的 OAuth 授权流程。
  • API 限制 (API Limits):

    Named Credentials 是一种管理认证和端点的机制,它不会绕过 Salesforce 的 Governor Limits。每个 Apex 事务中允许的 callout 总数(同步为 100 次)和总的 callout 超时时间等限制依然适用。

  • 错误处理 (Error Handling):

    集成代码必须具备健壮的错误处理能力。如果认证失败(例如,密码错误、OAuth token 被吊销),`http.send(req)` 会抛出 `System.CalloutException`。此外,即使认证成功,外部服务也可能返回非 2xx 的 HTTP 状态码(如 404 Not Found, 500 Internal Server Error)。务必检查 `res.getStatusCode()` 并妥善处理各种可能的响应。

  • 部署与包管理 (Deployment & Packaging):

    Named Credentials 和 External Credentials 都是元数据类型,可以包含在变更集 (Change Sets) 或通过 Metadata API 进行部署。但是,出于安全考虑,任何机密信息(如密码、客户端密钥)都不会在部署时被迁移。部署完成后,目标组织 (Org) 的管理员必须手动重新输入这些机密信息。这是确保生产环境安全的关键设计。

  • 命名空间 (Namespaces):

    在受管包 (Managed Package) 中,Named Credential 的名称会自动添加包的命名空间前缀。在代码中引用时,应使用 `callout:namespace__Credential_Name/path` 的格式。

  • 合并字段的安全性 (Security of Merge Fields):

    Named Credential 提供了在 HTTP 头部和请求体中使用公式合并字段的功能。虽然这很强大,但也需要警惕潜在的安全风险。如果合并字段的值来源于用户输入,必须进行严格的清理和验证,以防止注入攻击 (Injection Attacks)。


总结与最佳实践

对于任何 Salesforce 集成工程师来说,Named Credentials 都是工具箱中不可或缺的核心工具。它通过将认证细节和端点配置从业务逻辑中抽象出来,极大地提升了集成的安全性、可维护性和灵活性。

以下是我的核心建议和最佳实践:

  1. 永远不要硬编码凭据:这是集成的第一原则。始终使用 Named Credentials / External Credentials 组合来管理所有外部服务的认证信息。
  2. 拥抱新架构:优先使用现代的 External Credential + Named Credential 模式。它提供了更强的模块化和灵活性,是 Salesforce 未来的发展方向。
  3. 选择正确的认证模式:仔细评估你的业务场景。对于系统间的集成,使用 Named Principal;当操作需要以特定用户的身份执行时,务必使用 Per User 模式。
  4. 实现配置与代码分离:Named Credentials 的最大优势之一是管理员可以在不修改和重新部署代码的情况下,更新 API 端点或刷新凭据。这大大加快了维护速度。
  5. 为不同环境制定策略:为开发、测试 (UAT) 和生产环境创建不同的 Named Credentials。例如,`MyAPI_DEV`、`MyAPI_UAT`、`MyAPI_PROD`,它们可以指向同一个 External Credential,但在各自的 Salesforce 环境中指向外部服务的相应环境 URL。
  6. 编写防御性代码:始终假设 callout 可能会失败。使用 `try-catch` 块,检查 HTTP 状态码,并为最终用户提供清晰的错误信息或重试机制。

通过遵循这些原则,你可以构建出既强大又安全、易于维护的 Salesforce 集成解决方案,真正发挥 Salesforce 平台作为企业应用中心的连接价值。

评论

此博客中的热门博文

Salesforce 登录取证:深入解析用户访问监控与安全

Salesforce Experience Cloud 技术深度解析:构建社区站点 (Community Sites)

Salesforce Einstein AI 编程实践:开发者视角下的智能预测