適用於伺服器對伺服器整合的 OAuth 2.0 JWT 承載者流程
有時您會想要授權伺服器來存取資料,而不需在每次伺服器交換資訊時透過互動方式登入。針對這些情況,您可以使用 OAuth 2.0 JSON Web 權杖 (JWT) 承載者流程。此流程使用憑證來簽署 JWT 要求,且不需要明確使用者互動。然而,此流程確實需要用戶端應用程式的事先批准。
必要版本
| 提供版本:Salesforce Classic 與 Lightning Experience |
| 提供版本:所有版本 |
透過 OAuth 2.0 JWT 承載權杖流程,用戶端將 JWT 張貼到 Salesforce OAuth 權杖端點。Salesforce 會處理包含數位簽章的 JWT,並根據應用程式的事先核准發出存取權杖。
此範例顯示在流程中採取的步驟。
- 報告服務會開始其夜間批次報告。
- 連線的應用程式會將 JWT 傳送至 Salesforce 權杖端點。JWT 允許安全性網域之間共用身分與安全性資訊。
- Salesforce 會使用先前設定的憑證和其他參數,根據簽章來驗證 JWT。
- 假設 JWT 是有效的,且連線應用程式具有事先的批准,Salesforce 就會核發存取權杖。事先批准的發生方式為以下其中一種:
- 若您的連線應用程式原則設為「管理員批准的使用者均獲得預先授權」,即可使用設定檔和權限集。
- 若您的連線應用程式原則設為「所有使用者均可自我授權,即可使用一般使用者批准及核發重新整理權杖。然而,用戶端不需要具備目前或儲存的重新整理權杖。用戶端也不需傳送用戶端密碼給權杖端點。
備註 針對這兩個選項,Salesforce 只會在原始存取權杖包含至少一個refresh_token範圍以外的標準範圍時核發新的存取權杖。 - 連線應用程式使用存取權杖來在 Salesforce 伺服器上存取受保護的資料。
- 報告服務會將授權的資料提取至其夜間報告。
讓我們檢視此授權流程中的每個步驟。
建立 JWT
Salesforce 需要使用 RSA SHA256 來簽署 JWT,且其使用已上載的憑證作為簽署金鑰。使用此授權流程之前,請確保您完成下列步驟。
- 將「X509 憑證」上載至 Java Key Store (JKS)。憑證大小不能超過 4 KB。若超過,請嘗試使用 DER 編碼的檔案來減少大小。
- 為連線的應用程式註冊「X509 憑證」。此憑證會對應到應用程式的私人金鑰。儲存連線的應用程式時,會產生
client_id和client_secret並指派給應用程式。 - 建立會產生 JWT 的應用程式,系統會使用「X509 憑證」的私人金鑰來簽署 JWT。關聯的連線應用程式會使用憑證來確認簽章。JWT 必須符合 https://tools.ietf.org/html/rfc7519 中指定的一般格式規則。
備註 Salesforce 不需要您 JWT 承載者權杖中的 JWT ID (JTI) 宣告。不過,如果您傳送 JWT 承載者權杖中的 JTI 宣告,Salesforce 會驗證 JTI 宣告之前是否並未傳送。此驗證會防止 JWT 重新執行攻擊。
若要建立有效的 JWT,請執行下列步驟。
- 建置下列格式的 JWT 標題:
{"alg":"RS256"}. - Base64url 編碼 JWT 標頭,如 http://tools.ietf.org/html/rfc4648#page-7 中所定義。結果類似於
eyJhbGciOiJSUzI1NiJ9。 - 使用以下參數來建構 JWT 的 JSON 宣告集。
這裡是 JWT 的範例 JSON 宣告集。參數 描述 iss核發者必須包含您已註冊憑證之連線應用程式的 OAuth client_id。aud受眾會將授權伺服器識別為預期的受眾。授權伺服器必須驗證其為權杖的預期受眾。
使用授權伺服器的 URL 作為受眾値。https://login.salesforce.com、https://test.salesforce.com 或是 https://site.force.com/customers (若是針對 Experience Cloud 網站實作)。
sub若您針對 Experience Cloud 網站實作此流程,則主題必須包含使用者的使用者名稱。
如需回溯相容性,您可以使用主體 (
prn),而非主體 (sub)。如果兩者皆有指定,則會使用prn。exp權杖到期的日期和時間,以 1970-01-01T0:0:0Z UTC 測量的秒數表示。Salesforce 允許 3 分鐘緩衝的時間誤差。例如,如果到期時間設定為 1,735,743,600 秒或 2025 年 1 月 1 日 15:00:00 UTC,則權杖直到此日期的 15:03:00 UTC 為止仍有效。 {"iss": "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQ ukXnVjzRgSuQqGn75NL7yfkQcyy7", "sub": "my@email.com", "aud": "https://login.salesforce.com", "exp": "1333685628"} - Base64url 會編碼沒有分行的 JWT 宣告集。例如:
eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoOUFLTF9yU0su Qm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsICJwcm4iOiAibXlAZW1haWwu Y29tIiwgImF1ZCI6ICJodHRwczovL2xvZ2luLnNhbGVzZm9yY2UuY29tIiwgImV4cCI6ICIxMzMz Njg1NjI4In0= - 以此格式建立編碼 JWT 標題和編碼 JWT 宣告集的字串。
此範例中醒目提示經過編碼的 JWT 標頭。encoded_JWT_Header + "." + encoded_JWT_Claims_SeteyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoOUFLTF9yU0su Qm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsICJwcm4iOiAibXlAZW1haWwu Y29tIiwgImF1ZCI6ICJodHRwczovL2xvZ2luLnNhbGVzZm9yY2UuY29tIiwgImV4cCI6ICIxMzMz Njg1NjI4In0= - 從 JKS 下載「X509 憑證」。
- 使用 RSA SHA256 簽署結果字串。
- 以此格式建立此步驟字串的字串。
此範例中已醒目提示以 base64 編碼的簽章。existing_string + "." + base64_encoded_signatureeyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoOUFLTF9yU0su Qm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsICJwcm4iOiAibXlAZW1haWwu Y29tIiwgImF1ZCI6ICJodHRwczovL2xvZ2luLnNhbGVzZm9yY2UuY29tIiwgImV4cCI6ICIxMzMz Njg1NjI4In0=.iYCthqWCQucwi35yFs-nWNgpF5NA_a46fXDTNIY8ACko6BaEtQ9E6h4Hn1l_pcwcK I_GlmfUO2dJDg1A610t09TeoPagJsZDm_H83bsoZUoI8LpAA1s-2aj_Wbysqb1j4uDToz 480WtEbkwIv09sIeS_-QuWak2RXOl1Krnf72mpVGS4WWSULodgNzlKHHyjAMAHiBHIDNt 36y2L2Bh7M8TNWiKa_BNM6s1FNKDAwHEWQrNtAeReXgRy0MZgQY2rZtqT2FcDyjY3JVQb En_CSjH2WV7ZlUwsKHqGfI7hzeEvVdfOjH9NuaJozxvhPF489IgW6cntPuT2V647JWi7ng
此 Java 程式碼是建置 JWT 承載者權杖的一個簡單範例。
import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.security.*;
import java.text.MessageFormat;
public class JWTExample {
public static void main(String[] args) {
String header = "{\"alg\":\"RS256\"}";
String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\", \"jti\": \"{4}\"'}'";
try {
StringBuffer token = new StringBuffer();
//Encode the JWT Header and add it to our string to sign
token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));
//Separate with a period
token.append(".");
//Create the JWT Claims Object
String[] claimArray = new String[5];
claimArray[0] = "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7";
claimArray[1] = "my@email.com";
claimArray[2] = "https://login.salesforce.com";
claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
claimArray[4]=<JTI>
MessageFormat claims;
claims = new MessageFormat(claimTemplate);
String payload = claims.format(claimArray);
//Add the encoded claims object
token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")));
//Load the private key from a keystore
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("./path/to/keystore.jks"), "keystorepassword".toCharArray());
PrivateKey privateKey = (PrivateKey) keystore.getKey("certalias", "privatekeypassword".toCharArray());
//Sign the JWT Header + "." + JWT Claims Object
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(token.toString().getBytes("UTF-8"));
String signedPayload = Base64.encodeBase64URLSafeString(signature.sign());
//Separate with a period
token.append(".");
//Add the encoded signature
token.append(signedPayload);
System.out.println(token.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}要求存取權杖
若要要求存取權杖,則連線應用程式會將權杖要求張貼至 Salesforce 例項的權杖端點。其在貼文中包含 JWT。
此範例提供權杖要求樣本。
POST /services/oauth2/token HTTP/1.1
Host: login.example.com
Content-Type: application/x-www-form-urlencoded
grant_type= urn:ietf:params:oauth:grant-type:jwt-bearer&
assertion=eyJpc3MiOiAiM01WRz...[omitted for brevity]...ZT在貼文中包含這些參數。
| 參數 | 描述 |
|---|---|
grant_type
|
將這些值用在授與類型:urn:ietf:params:oauth:grant-type:jwt-bearer. |
assertion
|
判斷是整個 JWT 值。 |
format
|
(選用) 用於指定預期的傳回格式。此參數會覆寫要求的標題。支援這些格式。
|
範圍參數
您無法在 JWT 承載者權杖流程中指定範圍。範圍會根據連線應用程式的「允許的使用者」原則或您組織的 API 存取控制設定核發,如下表所示。
| 設定 | 結果 |
|---|---|
| 允許的使用者原則:所有使用者均可自我授權 | 成功授權後,會從先前批准的範圍衍生出使用存取權杖傳回的範圍。 |
| 允許的使用者原則:管理員核准的使用者均獲得預先授權 | 系統會傳回存取權杖,以及指派給連線應用程式的標準和自訂範圍。 |
| API 存取控制:您組織中允許清單連線的應用程式 | 系統會傳回存取權杖,以及指派給連線應用程式的標準和自訂範圍。如果您將組織中的連線應用程式列入允許清單,且未收到預期的範圍,請執行下列步驟。
|
Salesforce 授與存取權杖
OAuth 2.0 JWT 承載者和 SAML 判斷式承載者流程要求會查看使用者先前包含重新整理權杖的批准。若 Salesforce 找到相符的批准,便會合併已批准範圍的值。Salesforce 接著會核發存取權杖。若 Salesforce 找不到先前批准 (內含重新整理權杖或任何可用的批准範圍),則系統會將要求視為未授權而失敗。
成功驗證後,Salesforce 例項會將回應傳送至連線應用程式。OAuth 2.0 JWT 承載者權杖流程的權杖回應會遵循與授權代碼流程相同的格式,雖然從未核發過重新整理權杖。
此範例中顯示 Salesforce 的回應。
{"access_token":"00Dxx0000001gPL!AR8AQJXg5oj8jXSgxJfA0lBog.
39AsX.LVpxezPwuX5VAIrrbbHMuol7GQxnMeYMN7cj8EoWr78nt1u44zU31
IbYNNJguseu",
"scope":"web openid api id","instance_url":"
https://yourInstance.salesforce.com","id":"
https://yourInstance.salesforce.com
/id/00Dxx0000001gPLEAY/005xx000001SwiUAAS","token_type":"Bearer"}這些參數出現在回應的內文中。
| 參數 | 描述 |
|---|---|
access_token |
OAuth 權杖,連線應用程式會使用此權杖來代表用戶端應用程式,要求對受保護資源的存取權。範圍格式的其他權限可能會隨附存取權杖。 |
token_type |
Bearer 權杖類型,用於包含存取權杖的所有回應。 |
scope |
會根據連線應用程式的「允許的使用者」原則或您組織的「API 存取控制」設定來核發範圍。請參閱範圍參數。 |
instance_url |
指示使用者組織例項的 URL。例如:https://yourInstance.salesforce.com/. |
id |
身分 URL,此 URL 可用來識別使用者與查詢使用者的詳細資訊。請參閱身分 URL。 |
sfdc_site_url |
如果使用者是 Experience Cloud 網站的成員,則會提供網站 URL。 |
sfdc_site_id |
如果使用者是 Experience Cloud 網站的成員,則會提供使用者網站的識別碼。針對 Experience Cloud 網站,此流程會在權杖端點中包含 "sfdc_site_id" 值。Connect REST API 要求可能需要此網站識別碼。 |

