掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
譯者 | 張?jiān)霰?/p>

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序設(shè)計(jì)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了隆化免費(fèi)建站歡迎大家使用!
審校 | 梁策 孫淑娟
對于某些用例,API密鑰就足夠了。但另一些情況下,出于安全和靈活的考慮,還需要JSON Web令牌(JWT)授權(quán)。所以要比較API密鑰和JWT授權(quán)兩個(gè)方案,具體方案還需具體分析。
具有合理ACL的API密鑰可以在不增加太多開銷的情況下提供足夠的安全性。但是,隨著微服務(wù)的使用在各種大小任務(wù)中增加,API生態(tài)系統(tǒng)可能會需要像JWT授權(quán)方案這樣更統(tǒng)一、更細(xì)粒度、更安全的方案。
對使用基于云的搜索API的在線企業(yè)來說,只要數(shù)據(jù)的基礎(chǔ)索引不包含任何機(jī)密信息,通常可以公開只讀API密鑰,而不會帶來很大風(fēng)險(xiǎn)。
事實(shí)上,出于性能考慮,客戶端應(yīng)用程序應(yīng)該直接連接到云搜索引擎,從而公開其API密鑰——以避免在進(jìn)入云之前更長時(shí)間地訪問后端服務(wù)器。 另一方面,索引更新需要限制對API密鑰的訪問,而這些API密鑰不應(yīng)被公開。
在這兩個(gè)用例(搜索和索引)中,API密鑰通常都很不錯(cuò),無需在JWT 授權(quán)上耗費(fèi)金錢。
API需要越來越靈活,也越來越需要保護(hù)。
JWT授權(quán)不僅額外提高了安全級別(詳見下文),還提供了一種更易于管理、更簡單的方法來協(xié)調(diào)日常中使用大量的API網(wǎng)絡(luò)。
JWT通過生成包含用戶和應(yīng)用程序級別信息(加密或散列)的單個(gè)共享令牌來集中身份驗(yàn)證和授權(quán),以幫助同一生態(tài)系統(tǒng)中的所有API確定允許令牌 持有者執(zhí)行的操作。
乍一看,API的密鑰似乎很簡單,你只需要發(fā)送正確的API密鑰,就可以開始使用,但這好得有點(diǎn)不真實(shí)。
當(dāng)生態(tài)系統(tǒng)依賴于許多集成的微服務(wù)時(shí),大量API密鑰管理將會變得混亂、不可靠甚至幾乎無法進(jìn)行。
它們會有數(shù)量增加、更改、過期、被刪除、ACL更改等等情況,而不通知依賴這些相同API密鑰的應(yīng)用程序和用戶。
API密鑰直接、簡單且完全透明。它們不代表任何基礎(chǔ)信息,不加密秘密消息,只是不可讀的唯一ID。
下面是一個(gè)在客戶端javascript中公開可用的API密鑰的示例:
該代碼包括一個(gè)App ID(app-id-BBRSSHR),它使用API密鑰(temp-search-key-ere452sdaz56qsjh565d)進(jìn)行搜索。
App ID 是指一個(gè)面向用戶的應(yīng)用程序(如在線網(wǎng)站或流媒體服務(wù))。API 密鑰是臨時(shí)的,它在一段時(shí)間后就過期,從而具有一定保護(hù)作用,能防止不必要的使用或?yàn)E用。
import { hitTemplate } from "./helpers";
const search = instantsearch({
appId: "app-id-BBRSSHR",
apiKey: "temp-search-key-ere452sdaz56qsjh565d",
indexName: "demo_ecommerce"
});
另一個(gè)例子是索引,它需要一個(gè)更安全的API密鑰。它有相同的格式(appId+apiKey),但其秘鑰要么在編譯代碼中,要么在后端的安全數(shù)據(jù)庫中,因而對公眾隱藏且為私有。
App ID (YourApplicationID) 是指后臺系統(tǒng)。 API 密鑰 (YourAdminAPIKey) 可以是一個(gè)永久的管理密鑰,每年只更改一次以簡化維護(hù)。
use Algolia\AlgoliaSearch\SearchClient;
$client = SearchClient::create(
'YourApplicationID',
'YourAdminAPIKey'
);
$index = $client->initIndex('demo_ecommerce');
$index->saveObject(
[
'firstname' => 'Jimmie',
'lastname' => 'Barninger',
'city' => 'New York',
'objectID' => 'myID'
]
);
JWT令牌是一大串不可讀的字符,其中包含的信息已隱藏和編碼,被簽名或加密算法覆蓋。它由三部分組成:頭部(header)、主體(body)和簽名(signature),
由句點(diǎn)分隔:Header.Body.Signature。
EZPZAAdsqfqfzeezarEUARLEA.sqfdqsTIYfddhtreujhgGSFJ.fkdlsqEgfdsgkerGAFSLEvdslmgIegeVDEzefsqd
EZPZAADSQFZEEZAREUARLEA是JWT頭,其中包含以下信息:
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
我們有不同的算法可用,例如 RS256 和 HS256。 這里我們使用 HS256算法,它需要在生成簽名時(shí)使用私鑰,RS256則使用私鑰和公鑰組合。
sqfdqsTIYfddhtreujhgGSFJ是 JWT 主體(稱為有效負(fù)載),其中包含用戶的身份,以幫助確立令牌用戶的權(quán)利。 它還提供過期日期(越短越安全)等其他信息。
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
fkdlsqEgfdsgkerGAFSLEvdslmgIegeVDEzefsqd是JWT簽名 ,它如頭部所示,通過使用 HS256 散列方法組合頭部、主體和共享私鑰組合生成。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
這樣你就得到了相應(yīng)的令牌:Header.Body.Signature:
EZPZAAdsqfqfzeezarEUARLEA.sqfdqsTIYfddhtreujhgGSFJ.fkdlsqEgfdsgkerGAFSLEvdslmgIegeVDEzefsqd
API密鑰和JWT都用于身份驗(yàn)證和授權(quán),但方式有所不同。
進(jìn)行身份驗(yàn)證和授權(quán)時(shí),API密鑰使用相同的API密鑰,JWT授權(quán)則需要在生成授權(quán)令牌之前進(jìn)行初始身份驗(yàn)證。
一旦生成了令牌,它就可以在整個(gè)生態(tài)系統(tǒng)中使用,以確定令牌持有者能做什么和不能做什么。
此外,API密鑰驗(yàn)證的是應(yīng)用程序而不是用戶;而JWT同時(shí)對用戶和應(yīng)用程序進(jìn)行身份驗(yàn)證。當(dāng)然,你可以使用API密鑰進(jìn)行用戶級授權(quán),但它的設(shè)計(jì)并不完善——生態(tài)系統(tǒng)需要為每個(gè)用戶或會話id生成和管理API密鑰,這對系統(tǒng)來說是不必要的負(fù)擔(dān)。
在安全方面,API密鑰和JWT都容易受到攻擊。最好的安全措施是為所有端到端通信實(shí)施安全架構(gòu)。
不過,因?yàn)樗鼈冃枰浑[藏,API密鑰在歷史上不太安全。
你可以使用SSL/TLS/HTTPS隱藏密鑰,或者將密鑰的使用限制在后端進(jìn)程。但是,你不能控制所有API的使用,且API密鑰也可能會泄漏,同時(shí)HTTPS也并不總是可行方案等等。
在JWT中,由于令牌是散列/加密的,因此它具有更安全的方法,不太可能被公開。
API密鑰和JWT令牌之間最顯著的區(qū)別在于,JWT令牌是自包含的:它們包含API保護(hù)交易和確定令牌持有人權(quán)利粒度所需的信息。
相反,API密鑰使用其唯一性來獲得初始訪問;但是,API需要在中央表中找到與密鑰關(guān)聯(lián)的ACL,以精準(zhǔn)確定密鑰允許訪問的內(nèi)容。
通常,API密鑰只保障應(yīng)用程序?qū)蛹壍陌踩?,為每個(gè)用戶提供相同的訪問權(quán)限;而JWT令牌提供用戶級訪問。
JWT令牌可以包含過期日期和用戶標(biāo)識符等信息,以確定用戶在整個(gè)生態(tài)系統(tǒng)中的權(quán)限。
讓我們看一下JWT令牌中可以包含的一些信息:
例子:
{
"iss": "stackoverflow",
"sub": "joe",
"aud": ["all"],
"iat": 1300819370,
"exp": 1300819380,
"jti": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
"context":
{
"user":
{
"key": "joe",
"displayName": "Joe Smith"
},
"roles":["admin","finaluser"]
}
}
JWT授權(quán)具有靈活性、可靠性和更高的安全性
下面是一個(gè)使用場景:
當(dāng)有很多的API在運(yùn)行時(shí),就會出現(xiàn)問題。這些訪問所需的 100 多個(gè) API 密鑰要存儲在哪里呢?管理過多的API密鑰需要為生態(tài)系統(tǒng)中運(yùn)行的所有應(yīng)用程序提供一個(gè)API密鑰表。
因此,生態(tài)系統(tǒng)中的每個(gè)應(yīng)用程序都必須了解數(shù)據(jù)庫,都需要連接并讀取該密鑰表。此外,一些應(yīng)用程序?qū)⒈辉试S生成新密鑰或修改現(xiàn)有密鑰。
所有這些都是不錯(cuò)的方式,但很難維護(hù)。管理這問題的一種方法是創(chuàng)建一個(gè)API,API根據(jù)該數(shù)據(jù)庫來驗(yàn)證密鑰。但為此你需要第二個(gè)身份驗(yàn)證系統(tǒng)來連接到這個(gè)API。
不僅檢索API密鑰很繁瑣,維護(hù)其持續(xù)時(shí)間和授權(quán)級別也是冗長的過程,而且并不是每個(gè)應(yīng)用程序都在應(yīng)用程序級別運(yùn)行,它們需要用戶級別的權(quán)限。
此外,API的使用方式因系統(tǒng)而異。更糟糕的是,不同的應(yīng)用程序共享API密鑰,因此要依賴不同的應(yīng)用程序來維護(hù)對共享API密鑰的正確訪問級別。
任何需要身份驗(yàn)證的API都可以輕松切換到JWT的授權(quán)。通過JWT授權(quán),你可以獲得基于用戶的身份驗(yàn)證。一旦用戶通過身份驗(yàn)證,用戶就會獲得一個(gè)可以在所有系統(tǒng)上使用的安全令牌。
用戶(以及令牌)采用集中方式的管理。你設(shè)置訪問權(quán)限,并為每個(gè)系統(tǒng)賦予每個(gè)用戶不同的權(quán)限。JWT授權(quán)端點(diǎn)對用戶進(jìn)行身份驗(yàn)證并創(chuàng)建令牌。
使用這種架構(gòu),下一步就是在整個(gè)生態(tài)系統(tǒng)中創(chuàng)建一個(gè)單點(diǎn)的登錄,并只依賴令牌來獲得權(quán)限。
最后,最簡單、最穩(wěn)健、最易管理的方法是創(chuàng)建一個(gè)專門用于身份驗(yàn)證和授權(quán)的單一端點(diǎn),這樣整個(gè)生態(tài)系統(tǒng)中的所有其他服務(wù)器都可以依賴該中心點(diǎn)來授權(quán)客戶端和服務(wù)器之間的API交互。
作為一名應(yīng)用程序開發(fā)人員,我在構(gòu)建API時(shí)主要關(guān)心它們是否得到了正確的使用,并提供了正確的數(shù)據(jù)和功能。
因此,我在很大程度上遵從DevOps的想法來推薦最佳和最易管理的安全措施。
但是,除了安全之外還有其他問題需要關(guān)注。在一個(gè)大型的生態(tài)系統(tǒng)中,我們需要一種簡單而穩(wěn)健的方式來跨多個(gè)系統(tǒng)和服務(wù)器訪問微服務(wù),而這最好通過集中身份驗(yàn)證和授權(quán)過程來實(shí)現(xiàn)。
在以下兩種情況下,選用JWT顯得有些“過猶不及”:
第三方API一般易于使用和快速實(shí)現(xiàn),集成時(shí)只需要很少的前期工作。
此外,你需要共享用于簽名令牌的密鑰。所以最好控制兩端,而這在第三方場景中是不可能的,并且你還需要信任實(shí)現(xiàn)。例如,API可以選擇忽略過期日期或有效起始日期(“not before”)。
不過,JWT 在以下情況就很有必要了:

我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流