前言
本篇所講案例代碼全部由上篇《IdentityServer4實戰:快速入門》修改而來。
客戶端模式
客戶端模式只對客戶端進行授權,不涉及到用戶信息。如果你的api需要提供到第三方應用,第三方應用自己做用戶授權,不需要用到你的用戶資源,就可以用客戶端模式,只對客戶端進行授權訪問api資源。 這是一種最簡單的模式,只要client請求,我們就將AccessToken發送給它。這種模式是最方便但最不安全的模式。因此這就要求我們對client完全的信任,而client本身也是安全的
定義 Client
new Client
{
ClientId = "client1",
// 沒有交互性用戶,使用 clientid/secret 實現認證。
AllowedGrantTypes = GrantTypes.ClientCredentials,
// 用於認證的密碼
ClientSecrets =
{
new Secret("secret".Sha256())
},
// 客戶端有權訪問的范圍(Scopes)
AllowedScopes = { "api1" }
}
POSTMan 測試

用戶名密碼模式
需要客戶端提供用戶名和密碼,密碼模式相較於客戶端憑證模式。通過User的用戶名和密碼向Identity Server申請訪問令牌。 這種方式需要用戶給出自己的用戶名/密碼,顯然風險很大,因此只適用於其他授權方式都無法采用的情況,而且必須是用戶高度信任的應用。
定義 Client
new Client
{
ClientId = "client2",
// 用戶名 密碼 模式
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
// 用於認證的密碼
ClientSecrets =
{
new Secret("secret".Sha256())
},
// 客戶端有權訪問的范圍(Scopes)
AllowedScopes = { "api1" }
}
定義 用戶資源
public static List<TestUser> GetTestUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId="1",
Username="admin",
Password="123456"
}
};
}
注冊 用戶資源
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryClients(Startup.GetClients())
.AddInMemoryApiScopes(Startup.GetApiScopes())
.AddTestUsers(Startup.GetTestUsers())
;
}
POSTMan 測試

隱藏式 (implicit)
有些 Web 應用是前后端分離的純前端應用,沒有后端。這時就必須將令牌儲存在前端。 這種方式沒有授權碼這個中間步驟,所以稱為(授權碼)"隱藏式"(implicit)。
隱藏式的認證步驟為:
第一步,A 網站提供一個鏈接,要求用戶跳轉到 認證中心,授權用戶數據給 A 網站使用。
第二步,用戶跳轉到 認證中心,登錄后同意給予 A 網站授權。這時,認證中心就會跳回redirect_uri參數指定的跳轉網址,並且把令牌作為 URL 參數,傳給 A 網站。
注意,令牌的位置是 URL 錨點(fragment),而不是查詢字符串(querystring),這是因為 OAuth 2.0 允許跳轉網址是 HTTP 協議,因此存在"中間人攻擊"的風險,而瀏覽器跳轉時,錨點不會發到服務器,就減少了泄漏令牌的風險。
安裝 登錄界面
隱藏式 需要用戶在 認證中心 登錄並授權數據給 A 網站,所以需要一個登錄界面。這里我們使用 官網提供的 Quickstart.UI,它提供了一個完善的登錄和登出的UI。
進入到 MicroShell.IdentityServer4.Server 項目根目錄,執行如下命令:
dotnet new -i identityserver4.templates dotnet new is4ui
安裝成功后,項目中多了 wwwroot、Quickstart、views 等文件夾。
注入 UI 的依賴服務 和 路由規則
ConfigureServices 方法中添加如下代碼:
services.AddControllersWithViews();
Configure 方法中路由改為:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
定義 Client
new Client
{
ClientId = "client4",
// 授權碼 模式
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris = { "http://localhost:5001/test/index"}, // 認證成功后允許的回調地址
// 是否需要確認授權,這個配置我們會在后面介紹,這里設置為 false
RequireConsent = false,
// 用於認證的密碼
ClientSecrets =
{
new Secret("secret".Sha256())
},
//AlwaysIncludeUserClaimsInIdToken=true,
//允許token通過瀏覽器 (必須 true)
AllowAccessTokensViaBrowser=true,
// 客戶端有權訪問的范圍(Scopes)
AllowedScopes = {
"api1",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
修改注入的 用戶資源

瀏覽器測試
瀏覽器輸入:http://localhost:5000/connect/authorize?response_type=id_token token&client_id=client4&scope=openid profile api1&redirect_uri=http://localhost:5001/test/index&nonce=11111111111111111111111

授權碼模式
授權碼(authorization code)方式,指的是第三方應用先申請一個授權碼,然后再用該碼獲取令牌。 這種方式是最常用的流程,安全性也最高,它適用於那些有后端的 Web 應用。授權碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。
定義 Client
new Client
{
ClientId = "client3",
// 授權碼 模式
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { "http://localhost:5001/test/index"},
// 是否需要確認授權,這個配置我們會在后面介紹,這里設置為 false
RequireConsent = false,
// 這個參數必須設置 為 false
RequirePkce= false,
// 用於認證的密碼
ClientSecrets =
{
new Secret("secret".Sha256())
},
// 客戶端有權訪問的范圍(Scopes)
AllowedScopes = {
"api1",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
瀏覽器測試
瀏覽器輸入:http://localhost:5000/connect/authorize?response_type=code&client_id=client3&state=xyz&redirect_uri=http%3A%2F%2Flocalhost%3A5001%2FTest%2Findex&scope=openid profile api1

尾言
授權碼模式中我們只拿到了 Code,並沒有通過 Code 換取 Token,后面的操作筆友可以自己實現。
本文轉載自:https://limitcode.com/detail/606d61e8d9118c3cd416878c.html
