精通 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 会在幕后完成以下所有工作:
- 解析 `My_Named_Credential_Name`,找到关联的 Named Credential 和 External Credential。
 - 根据 Principal 的配置,获取正确的认证凭据(是共享的系统凭据还是当前用户的凭据)。
 - 执行所选认证协议的流程。如果是 OAuth 2.0,它会检查 Access Token 是否有效,如果过期,会自动执行 Refresh Token 流程以获取新的 Access Token。
 - 将获取到的认证信息(例如,`Authorization: Bearer 
`)自动添加到 HTTP 请求的头部。  - 将请求发送到最终的 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 都是工具箱中不可或缺的核心工具。它通过将认证细节和端点配置从业务逻辑中抽象出来,极大地提升了集成的安全性、可维护性和灵活性。
以下是我的核心建议和最佳实践:
- 永远不要硬编码凭据:这是集成的第一原则。始终使用 Named Credentials / External Credentials 组合来管理所有外部服务的认证信息。
 - 拥抱新架构:优先使用现代的 External Credential + Named Credential 模式。它提供了更强的模块化和灵活性,是 Salesforce 未来的发展方向。
 - 选择正确的认证模式:仔细评估你的业务场景。对于系统间的集成,使用 Named Principal;当操作需要以特定用户的身份执行时,务必使用 Per User 模式。
 - 实现配置与代码分离:Named Credentials 的最大优势之一是管理员可以在不修改和重新部署代码的情况下,更新 API 端点或刷新凭据。这大大加快了维护速度。
 - 为不同环境制定策略:为开发、测试 (UAT) 和生产环境创建不同的 Named Credentials。例如,`MyAPI_DEV`、`MyAPI_UAT`、`MyAPI_PROD`,它们可以指向同一个 External Credential,但在各自的 Salesforce 环境中指向外部服务的相应环境 URL。
 - 编写防御性代码:始终假设 callout 可能会失败。使用 `try-catch` 块,检查 HTTP 状态码,并为最终用户提供清晰的错误信息或重试机制。
 
通过遵循这些原则,你可以构建出既强大又安全、易于维护的 Salesforce 集成解决方案,真正发挥 Salesforce 平台作为企业应用中心的连接价值。
评论
发表评论