如果使用 IdentityServer4 做授權服務的負載均衡,預設情況下是不可以的,比如有兩個授權服務站點,一個資源服務綁定其中一個授權服務( 配置),如果通過另外一個授權服務獲取 ,然後拿這個 去訪問資源服務,會報 401 未授權錯誤,為什麼?原因在這: By default an access ...
如果使用 IdentityServer4 做授權服務的負載均衡,預設情況下是不可以的,比如有兩個授權服務站點,一個資源服務綁定其中一個授權服務(Authority
配置),如果通過另外一個授權服務獲取access_token
,然後拿這個access_token
去訪問資源服務,會報 401 未授權錯誤,為什麼?原因在這:
By default an access token will contain claims about the scope, lifetime (nbf and exp), the client ID (client_id) and the issuer name (iss).
歸納一下,生成access_token
受影響的因素:
- scope(授權範圍):服務包含在 scope 內,生成的
access_token
,才能訪問本服務。 - lifetime(生命周期):過期的
access_token
,無效訪問。 - client ID (client_id):不同的客戶端 ID,生成不同對應的
access_token
。 - issuer name (iss):翻譯過來“發行者名稱”,類似於主機名。
- RSA 加密證書(補充):不同的加密證書,生成不同對應的
access_token
。
要讓負載均衡下的兩個授權服務,可以正常使用的話,需要確保兩台授權服務以上五種因素完全一致,除了 issuer name (iss),其他因素都是一樣的。
IdentityServer4 怎麼設置 issuer name (iss)呢?答案是通過IssuerUri
:
IssuerUri
:Set the issuer name that will appear in the discovery document and the issued JWT tokens. It is recommended to not set this property, which infers the issuer name from the host name that is used by the clients, If not set, the issuer name is inferred from the request.
說明中不建議我們進行設置,預設情況下,IdentityServer4 會從客戶端的主機名中獲取,可以認為,預設情況下,issuer name(IssuerUri
)就是授權服務的主機名(比如http://10.9.1.1:5000
)。
手動設置IssuerUri
代碼:
var builder = services.AddIdentityServer(x => x.IssuerUri = "http://111.12.2.21:8000"); //slb 地址
資源服務授權配置修改:
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://111.12.2.21:8000", //slb 地址
ApiName = "trade_refund",
RequireHttpsMetadata = false
});
獲取access_token
示例代碼:
var client = new DiscoveryClient("http://111.12.2.21:8000"); //必須是 slb 地址,如果是單獨的授權服務地址,會報錯誤(Value cannot be null. Parameter name: address)
client.Policy.RequireHttps = false;
var disco = await client.GetAsync();
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
var tokenResponse = tokenClient.RequestClientCredentialsAsync(scope);
var accessToken = tokenResponse.AccessToken;
通過 HTTP Post 獲取access_token
(不通過 slb,直接請求單獨的授權服務),可以授權訪問資源服務,獲取access_token
示例:
參考資料: