干过Salesforce开发的兄弟都有这个经历:客户扔过来一套集成需求,问“我们要从外部系统拉取数据,连接Salesforce怎么搞”,第一个要碰的就是Connected App。这东西听着高大上,其实就是一个OAuth 2.0的客户端注册入口,但没配置好,后面全是坑。
我见过不少团队在Connected App上翻车:回调地址写错导致登录白屏、Client Secret忘了重新生成、刷新令牌策略设成永不过期被安全审计揪出来、IP限制挡了正常用户。这篇文章我把Connected App从原理到实操完整走一遍,每个参数怎么选、为什么要这么选、选错会出什么问题,全部摊开讲,你看完直接照着配就行,不用再翻半个小时的官方文档。
1. 先搞懂它到底解决什么问题
1.1 Connected App的本质
Connected App本质上是Salesforce在平台上做的一个OAuth 2.0服务提供方接入点,外部系统通过它获取访问Salesforce各种API的令牌。类比一下:你想进一个小区,没有钥匙,但你有一张临时访客卡;Connected App就是发访客卡的管理处,它验证你的身份,给你发一张带有效期的通行证,也就是Access Token。
这个设计解决了一个核心问题:外部应用不该拿到Salesforce用户的账号密码。有了Connected App之后,外部系统通过标准OAuth流程去换取令牌,用户的敏感凭证始终留在Salesforce这边,安全性和可审计性都更强了。同时你可以针对每个Connected App单独配置权限范围、IP限制、会话超时、令牌有效期,做到精细化控制,而不是一个全局API账户一条路走到黑。
1.2 四种OAuth授权方式怎么选
Connected App支持多种OAuth流程,实际开发中最常用的是这四种:
| 授权方式 | 适用场景 | 关键特点 |
|---|---|---|
| Web App Flow | 有后端服务器的Web应用 | 用户跳转登录,授权码模式,可获得刷新令牌 |
| Device Flow | 命令行工具、无浏览器环境 | 用户在浏览器中输入验证码完成登录 |
| Username-Password Flow | 集成环境、服务账户 | 直接用用户名密码换令牌,不建议生产环境长期使用 |
| JWT Bearer Flow | 系统间集成、服务端对服务端 | 用证书签名换令牌,无需用户交互,最推荐 |
如果做的是系统集成类项目,我强烈建议优先考虑JWT Bearer Flow。原因很简单:它不依赖用户交互,整个过程中没有密码暴露,证书私钥只存放在应用服务器上,通过签名机制验证身份,安全性和自动化程度都更高。用户名密码流虽然配置简单,但意味着你在代码里硬编码了生产环境管理员账号的密码,这绝对是安全审计的重灾区。
1.3 动手前先想清楚的三个问题
配置Connected App之前,先把下面三个问题想明白,后面能少走很多弯路:
第一,这个应用对谁开放。只给内部几个集成账户用,还是允许所有登录用户通过它访问?这决定了后续在Permission Policy里怎么选,也影响IP限制要不要开。
第二,外部系统需要调哪些接口。操作的是标准对象、自定义对象还是Metadata API?这决定了OAuth Scopes怎么选,选取范围过大有安全风险,选漏了接口直接401。
第三,是否需要刷新令牌。很多集成场景是一次性任务,用短期Access Token就够了;但持续性的数据同步必须有Refresh Token,否则两小时过后Token过期,应用就瘫了。
2. 核心参数逐个拆解
2.1 Client ID、Client Secret与回调URL
这三个参数让人又爱又恨。Client ID就是OAuth协议里的消费者Key,外部系统用它标识自己;Client Secret相当于这个Key的密码,只生成一次,漏看了就得点“Manage Consumer Details”重新生成。每次生成Secret之前一定要想清楚:旧Secret一旦过期,所有还在用旧密钥的生产环境应用会瞬间大面积报错。我遇到过半夜里线上集成突然全挂的惨案,原因就是白天手欠重生成了一次密钥,没有同步更新到下游系统。
回调URL(Callback URL)是授权码模式下Salesforce把用户重定向回来的地址。这里有两个隐藏规则:第一,必须是HTTPS地址,除非你是在本地开发环境可以用http://localhost,生产环境写http会直接报错;第二,不支持通配符匹配,必须写具体URL。多环境部署让很多人在这一步栽跟头,处理办法是把每个环境的回调地址都注册进去,比如测试环境放https://test.example.com/callback,生产环境放https://app.example.com/callback,而不是试图用一个域名去兜底。
我见过的另一个高频失误是把回调URL写成了接口地址。回调URL写的是浏览器回跳的前端页面,不是后端接收Code的接口,两个经常被搞混。整个流程是:用户浏览器跳转登录 → Salesforce回调到页面 → 页面把Authorization Code传给后端 → 后端用Code换取Token。搞清楚这个链路,配置时就不容易出错。
2.2 OAuth Scopes和刷新令牌策略
OAuth Scopes定义了令牌可以访问的资源范围。对集成开发来说,最常用的是这几个:
- Full access:拥有当前用户的所有权限,测试阶段图省事会用,生产环境慎选
- Manage user data via APIs (api):可以读写当前用户有权限的数据,是最常用的范围
- Perform requests at any time (refresh_token, offline_access):允许获取刷新令牌
- Manage user data via Web browsers (web):供Web应用使用
- Access unique user identifiers (openid):用于OpenID Connect身份验证
我自己的习惯是“能少勾就少勾”。比如只做数据读写就只勾api和refresh_token;需要拿用户基本信息就看情况勾openid。权限给太宽,出了问题排查范围也大,审计那边也不好交代。
刷新令牌策略这里有个生产环境的细节值得单独说。默认情况下Refresh Token是永不过期的,这对持续集成是好事,但对安全审计来说就是靶子。新版Connected App里你可以通过设置Refresh Token的有效期来控制风险。关键点在于:到期后虽然Refresh Token失效,但第三方授权关系会被保留,用户不需要重新做OAuth授权。这是很多人不知道的特性,配置权限策略时可以放心地收紧有效期,业务影响很小。
2.3 签名证书与JWT Bearer
JWT Bearer Flow需要用到数字证书,这是集成方案里最关键的一环。流程是这样的:你先在Connected App里上传一个证书(通常用openssl生成私钥和自签名证书,导出cer公钥文件),外部系统持有私钥,用私钥对一段JSON请求体签名,发给Salesforce的Token Endpoint,Salesforce用之前上传的公钥验签,验签通过就颁发Access Token。
关于证书有效期,我个人的习惯是证书有效期一到两年,到期前提前一个月做轮换。轮换操作不难:在Connected App里先上传新证书,保留旧证书,让外部系统切换后再删掉旧证书,可以做到不中断业务。切忌直接在旧证书上覆盖,没有过渡期,出问题没法回滚。
3. 完整实操过程
3.1 从零创建Connected App的六个步骤
打开Setup,在快速查找框里输入App Manager,点New Connected App。这里我按最常见的Web App Flow来走一遍,JWT流程在关键的证书上传处会单独标注。
第一步,填基本信息。Connected App Name随便起,但要起得有意义,比如“SAP-Integration-App”,方便以后在日志里识别。API Name会自动生成,一般不用自己改。联系人邮箱必填,系统出安全公告时会发到这个地址。
第二步,启用OAuth Settings。勾上Enable OAuth Settings,Callback URL按前面说的填HTTPS地址。这里有一个新手容易踩的坑:不勾Enable OAuth Settings,后面的Client ID和Client Secret根本不会生成,保存完回来看不到消费者Key和消费者Secret,一脸懵。Selected OAuth Scopes按需勾选,Web App Flow建议勾上api和refresh_token。
第三步,如果是JWT Bearer方案,继续往下找到Use digital signatures,勾选后上传证书文件。没有这一步,JWT流程会在验签环节直接报错。上传的证书文件要求是.cer格式的公钥,密钥对生成用openssl命令就可以,非常成熟。
第四步,保存后回到App Manager列表,找到刚创建的记录,点击右侧下拉箭头,选择View。这里有一件很多人不知道的事:新创建的Connected App默认是“草稿状态”,需要在这里点Manage,再点Edit,把状态改成Activated才能用于授权。没有激活的连接应用,拿Client ID去请求Token会返回错误,这个问题经常被忽略。
第五步,点击Manage Consumer Details获取并保存Client ID和Client Secret。这个环节要开启双重验证,系统会要求输入验证码,把两条密钥信息安全地交给外部系统的开发人员。
第六步,配置权限和策略,这决定了谁能用、怎么用,我在下一节单独讲。
3.2 权限策略与用户授权的坑
创建完Connected App只是第一步,用户能不能成功拿到Token,取决于两个层面的授权:
第一个层面是App本身的Permission Policy。Edit Policies里有几个关键项:
- Permitted Users:选Admin approved users are pre-authorized,意思是只有列入名单的人才能授权,比较安全;选All users may self-audit,任何用户都能直接授权,适合内部全员使用的小工具
- IP Relaxation:限制允许授权的IP段。外部系统出口IP固定的话建议开起来,能挡掉一部分扫描和滥用
- Refresh Token Policy:按集成需要设置有效期
- Session Timeout:会话超时时间,默认两小时,通常设置成业务可接受的范围就可以
第二个层面是用户Profile / Permission Set的权限。很多人创建的Connected App接完发现外部账户登录时报错“This app is blocked by your administrator”,原因就是用户连查看这个Connected App的权限都没有。解决方案是给对应用户的Permission Set里加上“Manage Connected Apps”或对该App的Access权限。我的习惯是单独建一个“Integration Access”权限集,把相关Profile和 User都挂上去,清晰好管理。
另外还有一个细节:Connected App的权限策略即使改完,也不是马上生效,Salesforce有缓存同步时间,一般一两分钟内会更新。我遇到过一次线上改完策略测试还是报错,等了差不多一分钟突然就好了。如果改了权限之后还是老错误,等一会儿再试。
3.3 用curl验证整个链路
配置完成后先用curl做一次端到端验证,比直接联调省心得多。以JWT方案为例,先拿到断言(Assertion),用私钥对JSON请求体签名,然后请求Token Endpoint:
curl -X POST https://login.salesforce.com/services/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \ -d "assertion=YOUR_JWT_ASSERTION" \ -d "client_id=YOUR_CLIENT_ID"正常返回会得到一个JSON,里面包含access_token和instance_url。拿到access_token后,可以调一个简单的接口验证权限范围:
curl https://your-domain.my.salesforce.com/services/data/v59.0/sobjects/Account/ \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"如果返回200,说明整体链路通了。如果报错,按返回的错误码去查,大概率是下面几个问题:invalid_grant表示证书验签或用户名不对;invalid_client_id说明Client ID写错;unauthorized_client说明Scopes或权限策略没配好。
Web App Flow的验证步骤更复杂一点:先通过浏览器访问授权端点,拿到Code,再拿Code换Token。这个流程没法用一条curl直接完成,我会配合Postman来测,关键就是Authorization Code只能使用一次,失败后必须重新走授权页。
4. 常见问题与排查技巧实录
4.1 高频报错速查表
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
| error=invalid_client | Client ID或Client Secret错误 | 核对Get Consumer Details里的信息 |
| error=invalid_grant | 证书验签失败或用户不存在 | 检查证书是否匹配、用户名有无拼写错误 |
| error=unauthorized_client | 用户无权访问该App | 检查Profile/Permission Set权限 |
| error=invalid_client_id | 回调地址或Client ID格式不对 | 检查Client ID有没有复制完整 |
| error=unsupported_grant_type | grant_type参数拼写错误 | 核对授权方式参数 |
| 登录后页面跳回报错 | Callback URL配置错误 | 确认回调地址和Apex/CSP可信地址 |
这个表里的前四类问题占了日常排障的八成,大部分情况不是代码写得不好,而是Connected App配置层面的小纰漏。
4.2 沙盒环境与生产环境同步
一个很容易被忽略的问题是Sandbox和生产环境的Connected App并不自动同步。你在沙盒里配好了一切,部署到生产环境时如果只是把Metadata带过去,Consumer Secret会在部署中途被拦截,因为Secret属于安全敏感信息,不允许通过Metadata API直接读取。
解决办法是在生产环境手动创建一遍,或者通过Change Set / DevOps Center部署时选上Connected App的权限,之后重新获取Secret并同步给下游。千万别想着Metadata直接一套走天下,Secret这关卡得死死的,这是Salesforce故意的安全设计。
4.3 刷新令牌突然失效的排查
遇到过几次刷新令牌失效的情况,坐在一起排查,最终原因都很典型:
第一种是密码被重置或在设置里“撤销所有会话”导致OAuth授权失效。用户一旦重置密码,Salesforce会撤销关联的OAuth Token,旧的刷新令牌全部作废,必须重新授权。生产环境集成账户如果被安全团队重置了密码而没人知道,第二天定时任务就会默默报错。
第二种是在Connected App的Edit Policies里改了Scope或权限。每次修改Connected App的配置,会使基于旧配置签发的Token失活。所以配置改动要挑在窗口期做,改完下游应用需要重新授权。
第三种是刷新令牌过期策略配置得太短,没算好任务执行频率。比如设成24小时过期,但同步任务是每天凌晨3点跑,如果上次授权时间在3点多,下一次凌晨3点的同步就已经超时了,任务直接失败。
4.4 两个容易被忽略的隐藏设置
第一个是CORS(跨域资源共享)。如果你的前端页面是纯HTML/JavaScript应用,直接调用Salesforce API,也就是Pure JS集成场景,必须在CSP Trusted Sites里配置允许跨域的域名。没配CORS,浏览器控制台会报CORS错误,很多人排查半天都想不到是这里的问题。在Setup里搜CSP Trusted Sites,新增一条记录,填上前端域名,保存即可。
第二个是登录页域名。外部系统跳转授权时,默认走的是https://login.salesforce.com,如果你的Org启用了My Domain并且用了自定义域名,授权地址也要跟着调整。我见过有团队直接复制官方文档的地址,结果在自定义域名环境下怎么跳都404,改回自定义域名登录地址后问题立刻消失。
5. 从实践中总结的几个习惯
做Connected App配置做了几年,我现在有了几个固定的工作习惯,分享出来供你参考:
第一,所有环境用同一套命名规范。比如“PROD-SAP-INTEGRATION”、“UAT-SAP-INTEGRATION”,一看名字就知道是哪个环境、干什么用的,多人协作时不至于搞混。
第二,Client Secret绝不让外部团队直接来拿。我都是拿到后通过安全渠道传过去,同时明确告诉他们:密钥只能存到安全的密钥管理服务里,不许硬编码在代码仓库里。
第三,每个Connected App单独建一份授权清单,记录创建日期、负责人、回调地址、Scopes、刷新令牌策略、关联的集成系统、联系方式。这个清单在半年后做安全审计时是救命稻草,不用翻着一堆环境挨个回忆当初为什么这么配。
第四,定期检查App Manager里的Connected App列表,清理废弃的应用。账号轮换、项目下线之后经常忘了关掉旧的Connected App,这些遗留应用是潜在的安全漏洞点。看到一个就顺手停用,最小化攻击面。
配置Connected App看着是几分钟的点几下鼠标的事,但每一步选择背后都影响着后续集成的稳定和安全。我希望这篇文章能让你少踩几个坑。如果你在生产环境已经有跑着的Connected App,建议抽空把权限策略、刷新令牌有效性和IP限制这几项重新过一遍,大概率能找到可以收紧的地方。