目錄
目錄 1
第一章 IdentityServer3 1.x 5
v 超鏈接 5
Ø 概述 5
Ø 配置 5
Ø 端點 5
Ø 先進的 5
Ø 實體框架支持客戶、范圍和操作數據 6
Ø ws - federation 6
Ø 資源 6
第二章 概述 6
v 大局 6
v 術語 7
v OpenID提供者連接(鳳凰社) 8
v 客戶端 8
v 用戶 8
v 范圍 8
Ø 身份范圍 8
Ø 資源范圍 9
第三章 認證/令牌請求 9
v 身份標識 9
v 訪問令牌 9
v 特性和規格 9
v 包裝和構建 9
Ø 核心 9
Ø 配置商店 9
Ø 用戶存儲 9
Ø 插件 9
Ø 訪問令牌驗證中間件 10
v 開發構建 10
Ø 創建最簡單的OAuth2授權服務器,客戶端和API 10
Ø 設置IdentityServer 10
Ø 注冊的API 10
Ø 注冊客戶端 10
Ø 配置IdentityServer 11
Ø 托管IdentityServer 12
v 添加一個API 12
Ø 創建網絡主機 12
Ø 添加一個控制器 12
Ø 添加啟動 12
v 添加一個控制台客戶 13
v 添加一個用戶 13
Ø 添加一個用戶服務 13
Ø 添加一個客戶 14
Ø 更新的API 15
Ø 更新客戶端 15
v 下一步要做什么 16
v 第1部分- MVC身份驗證和授權 16
Ø 創建web應用程序 16
Ø 添加IdentityServer 17
Ø 配置IdentityServer -客戶 17
Ø 配置IdentityServer——用戶 18
Ø 添加啟動 18
Ø RAMMFAR 19
v 添加和配置OpenID身份驗證連接中間件 19
v 添加一個受保護的資源和Claims 19
Ø 身份驗證和Claims 20
Ø 添加角色和范圍 20
Ø 改變了中間件配置要求的角色 21
Ø 要求轉換 21
Ø 授權 23
Ø 資源授權 23
Ø 角色權限 24
Ø 更多的授權和處理拒絕訪問場景 24
Ø 添加注銷 25
Ø 添加谷歌身份驗證 26
v 第2部分-添加和調用Web API 27
Ø 添加Web API項目 27
Ø 添加一個測試控制器 28
Ø 連接在啟動Web API和安全 28
Ø 注冊在IdentityServer API 29
Ø 注冊一個Web API客戶端 30
Ø 調用API 30
Ø 代表用戶調用的API 32
第四章 配置 33
v 概述 33
v IdentityServer選項 34
v 服務工廠 34
v 強制性的 35
v 強制性的生產場景(但默認內存中實現) 35
v 可選(可以更換,但有默認的實現) 35
v 內存中的工廠 36
第五章 客戶 36
Ø 例如:為隱式流配置客戶端 37
Ø 例如:為資源所有者流配置客戶端 38
v 范圍和Claims 39
Ø Thinktecture.IdentityServer.Core.Models.Scope類的模型OpenID連接或OAuth2范圍。 39
v 身份驗證選項 40
v 身份提供者 41
v 添加ws - federation身份提供者 42
v HSTS 43
v CORS 43
v 歌珥政策服務 43
Ø 提供實現 43
v 棄用:CorsPolicy 43
Ø CorsPolicy 43
v 日志記錄 44
v 配置診斷 44
v 配置系統 診斷提供者 44
v 配置TraceSource提供者 45
v 插裝自己的代碼 45
v 事件 45
v 配置事件 45
第六章 端點 46
v 授權/身份驗證端點 46
Ø 支持參數 46
Ø 例子 46
v 令牌端點 47
Ø 支持參數 47
Ø 身份驗證 47
Ø 例子 47
v 用戶信息端點 48
Ø 例子 48
v 發現端點 48
Ø 例子 48
v 注銷端點 48
v 令牌撤銷 48
v 訪問令牌驗證端點 49
Ø 例子 49
v 身份令牌驗證端點 49
Ø 例子 49
v CSP端點 49
第七章 先進的 50
v 刷新令牌 50
Ø 設置在客戶端類 50
Ø 使用 50
Ø 樣品 50
v 定制服務 50
v 強制性的服務 50
v 注冊定制服務 50
Ø 服務清理 51
第八章 依賴注入 51
v 注入IdentityServer服務 51
v 注入定制服務 52
Ø 沒有一個接口定制服務 52
v 創建自定義 53
Ø 獲得其他依賴項 53
Ø 叫依賴 53
v 實例化與登記模式 53
v 客戶端緩存結果、范圍和用戶存儲 54
v 默認的緩存 54
v 自定義緩存 54
v 自定義視圖 54
Ø 默認視圖服務 54
Ø 自定義視圖服務 55
v 本地化的消息 56
v CSP 56
Ø CspOptions 56
v 用戶服務 56
v 身份驗證 57
Ø 驗證結果 57
第九章 部署 58
v 數據保護 58
v 終止SSL 58
v 簽名密鑰 59
v 配置數據 59
v 操作數據 59
v 緩存 59
第十章 實體框架支持客戶、范圍和操作數據 59
v 概述 59
v 配置客戶機和范圍 59
v 操作數據 59
v 客戶和范圍 59
v 商店 59
Ø ClientStore 59
Ø ScopeStore 59
v 登記 59
第十一章 操作數據 60
v 數據清理 60
第十二章 模式變化和遷移 60
v dbcontext 60
v 使遷移 60
第十三章 ws - federation 61
v 添加ws - federation支持 61
v 定義依賴方 62
v 端點 63
v 登錄/出 63
v 元數據 63
第十四章 資源 63
v 資源 63
Ø 規范 64
Ø 文章 64
Ø 視頻 64
Ø 培訓 64
v 社區插件 64
第十五章 中間件為外部認證 64
v 微軟的武士刀 64
v SAML2p 64
v 其他社區的貢獻 65
第一章IdentityServer3 1.x
v 超鏈接
Ø 概述
l 大局
l 術語
l 特性和規格
l 包裝
l 開始:創建最簡單的OAuth2授權服務器,客戶端和API
Ø 配置
l 概述
l 選項
l 服務工廠
l 內存中的工廠
l 客戶
l 身份驗證選項
l 身份提供者
l hst
l 歌珥
l 日志記錄
l 事件
Ø 端點
l 授權/身份驗證
l 令牌
l 用戶信息
l 發現
l 注銷
l 令牌撤銷
l 訪問令牌驗證
l 身份令牌驗證
l CSP錯誤報告
Ø 先進的
l 刷新令牌
l 注冊服務
l DI的服務
l 自定義視圖
l 本地化的消息
l CSP
l 用戶服務
l 部署
Ø 實體框架支持客戶、范圍和操作數據
l 概述
l 客戶和范圍
l 操作數據
l 模式變化和遷移
Ø ws - federation
l 定義依賴方
l 端點
Ø 資源
l 概述
l 社區插件
l 中間件為外部認證
第二章概述
v 大局
大多數現代應用程序看起來或多或少是這樣的:
典型的交互:
l 瀏覽器與web應用程序通信
l Web應用程序與Web api(有時自己,有時代表一個用戶)
l 基於瀏覽器的應用程序與web api通信
l 本機應用程序與web api通信
l 基於服務器的應用程序與web api通信
l Web api與Web api(有時自己,有時代表一個用戶)
通常每一層(中間層和后端,前端)和保護資源 實現身份驗證和/或授權,通常針對同一用戶存儲。
這就是為什么我們沒有實現這些基本安全功能的業務應用程序/端點本身, 而是關鍵功能的外包服務,安全令牌服務。
這將導致以下安全架構和使用協議:
這將安全問題划分為兩個部分。
u 身份驗證
身份驗證是必要的,當一個應用程序需要知道當前用戶的身份。 通常這些應用程序代表用戶管理數據,需要確保用戶只能 他被允許訪問數據。 最常見的例子(經典)web應用程序 但本機和JS-based應用程序也需要進行身份驗證。
最常見的身份驗證協議SAML2p,ws - federation,OpenID連接——SAML2p 最受歡迎和最廣泛的部署。
OpenID連接是最新的三個,但一般認為是,因為它有未來 現代應用最有潛力的產業。 它從一開始就為移動應用程序場景 和被設計成API友好。
u API訪問
應用程序有兩個基本方法,它們與api使用應用程序標識, 或授權用戶的身份。 有時兩方面需要的總和。
OAuth2是一種協議,它允許應用程序請求訪問令牌從安全令牌服務和使用它們 與api。 這降低了復雜性在客戶機應用程序的api 可以集中的身份驗證和授權。
OpenID和OAuth2——更好的聯系在一起
OpenID連接和OAuth2非常相似——事實上OpenID是一個連接擴展OAuth2之上。 這意味着您可以將兩個基本安全問題-認證和API訪問到一個單獨的協議 通常一個往返安全令牌服務。
這就是為什么我們相信OpenID的組合連接和安全的現代OAuth2是最好的方法 應用程序在可預見的未來。 IdentityServer3是這兩個協議的一個實現 高度優化的解決今天的移動的典型安全問題,本機和web應用程序。
v 術語
規范、文檔對象模型使用一個特定的術語,你應該知道的。
v OpenID提供者連接(鳳凰社)
IdentityServer OpenID提供者連接,它實現了OpenID連接協議(以及OAuth2)。
不同的文獻使用不同的條款相同的角色,你也可能找到安全令牌服務, 身份提供者,授權服務器,IP-STS等等。
但總而言之都是一樣的:一個軟件問題給客戶的安全令牌。
IdentityServer有很多工作和功能,包括:
l 驗證用戶使用本地帳戶存儲或通過外部身份提供者
l 提供會話管理和單點登錄
l 管理和認證的客戶
l 問題客戶身份和訪問令牌
l 驗證令牌
v 客戶端
客戶端是一個軟件,請求令牌從IdentityServer——對一個用戶進行身份驗證或 通常用於訪問資源(也稱為依賴方或RP)。 客戶端必須注冊與OP。
客戶是web應用程序的例子,本地移動或桌面應用程序,水療,服務器進程等。
v 用戶
用戶是一個人類,使用一個注冊客戶機來訪問他或她的數據。
v 范圍
作用域標識符為客戶想要訪問的資源。 這個標識符在一個發送給OP 身份驗證或令牌的請求。
默認情況下允許每個客戶機請求令牌為每個范圍,但是你可以限制。
他們有兩種口味。
Ø 身份范圍
請求關於用戶的標識信息(又名聲稱),如他的名字或電子郵件地址被建模為一個范圍的OpenID連接。
如有一個范圍profile首選,包括名字、姓、用戶名、性別、證件照以及更多。 你可以讀到標准范圍在這里你可以創建自己的范圍IdentityServer模型自己的需求。
Ø 資源范圍
資源范圍確定web api(也稱為資源服務器)——你可以如命名范圍calendar代表你的日歷API。
第三章認證/令牌請求
客戶請求令牌的相機會取決於請求的范圍,OP會返回一個身份令牌,一個訪問令牌,或兩者兼而有之。
v 身份標識
可以通過客戶端驗證身份令牌。
它包含有關用戶的信息和細節在OP用戶身份驗證。 身份令牌代表一個成功的身份驗證。
v 訪問令牌
一個訪問令牌可以由資源進行驗證。
客戶請求訪問令牌和轉發他們的API。 訪問令牌包含客戶端和用戶信息(如果存在)。 api使用這些信息來授權訪問他們的數據。
v 特性和規格
IdentityServer實現以下規格:
l OpenID連接核心1.0(規范)
l 基本的、隱含的和混合流
l OpenID連接發現1.0規范)
l OpenID連接會話管理1.0 - 22(草案規范)
l OAuth 2.0(RFC 6749)
l 授權代碼、隱式資源所有者密碼憑證和客戶端憑證
l OAuth 2.0不記名使用令牌(RFC 6750)
l OAuth 2.0多種反應類型(規范)
l OAuth 2.0表單Post響應模式(規范)
l OAuth 2.0令牌撤銷(RFC 7009)
v 包裝和構建
IdentityServer由nuget包的數量。
Ø 核心
包含核心IdentityServer對象模型、服務和服務器。 只包含核心支持內存配置和用戶的商店,但是你可以通過配置插件支持其他商店。 這是另一個回購和包。
Ø 配置商店
存儲配置數據(客戶和范圍)以及運行時數據(同意,令牌處理,刷新令牌)。
(社區貢獻)MongoDbgithub
Ø 用戶存儲
支持身份管理庫。
MembershipReboot nuget | github
ASP.Net Identity nuget | github
Ø 插件
協議插件。
Ø 訪問令牌驗證中間件
OWIN中間件api。 提供了一種簡便的方法來驗證訪問令牌和實施范圍的要求。
v 開發構建
此外,我們發布dev /臨時構建MyGet。 Visual Studio下面添加到你如果你想給他們一個嘗試:
https://www.myget.org/F/identity/
Ø 創建最簡單的OAuth2授權服務器,客戶端和API
這個介紹的目的是創建簡單的IdentityServer安裝作為一個OAuth2授權服務器。 這是應該讓你開始的一些基本特性和配置選項(可以找到完整的源代碼在這里)。 還有其他更高級的演練的文檔之后你可以做。 本教程包括:
l 創建一個自托管IdentityServer
l 為應用程序設置客戶服務通信使用應用程序帳戶和代表一個用戶
l 注冊一個API
l 請求訪問令牌
l 調用一個API
l 驗證一個訪問令牌
Ø 設置IdentityServer
首先,我們將創建一個控制台主機和設置IdentityServer。
首先創建一個標准的控制台應用程序並添加IdentityServer通過nuget:
install-package Thinktecture.IdentityServer3
Ø 注冊的API
api建模為范圍,你需要注冊所有api,你希望能夠請求訪問令牌。 為我們創建一個類返回的列表Scope:
using Thinktecture.IdentityServer.Core.Models;
static class Scopes{
public static List<Scope> Get()
{
return new List<Scope>
{
new Scope
{
Name = "api1"
}
};
}}
Ø 注冊客戶端
現在我們想注冊一個單一的客戶端。 這個客戶端可以請求的令牌api1范圍。 對於我們的第一次迭代,就沒有人類參與和客戶端只會請求令牌 代表本身(想想機對機通信)。 稍后我們將添加一個用戶。
這個客戶我們配置以下事情:
l 顯示名稱和id(唯一的名稱)
l 客戶端秘密(用於驗證客戶端對令牌端點)
l 流(客戶端憑證流在這種情況下)
l 所謂的參考標記的使用。 參考標記不需要簽名證書。
using Thinktecture.IdentityServer.Core.Models;
static class Clients{
public static List<Client> Get()
{
return new List<Client>
{
// no human involved
new Client
{
ClientName = "Silicon-only Client",
ClientId = "silicon",
Enabled = true,
AccessTokenType = AccessTokenType.Reference,
Flow = Flows.ClientCredentials,
ClientSecrets = new List<ClientSecret>
{
new ClientSecret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())
}
}
};
}}
Ø 配置IdentityServer
IdentityServer被實現為OWIN中間件。 中配置的Startup類使用UseIdentityServer擴展方法。 下面的代碼片段設置一個梗概服務器范圍和客戶。 我們還建立了一個空列表的用戶,我們稍后會添加用戶。
using Thinktecture.IdentityServer.Core.Configuration;using Thinktecture.IdentityServer.Core.Services.InMemory;
class Startup{
public void Configuration(IAppBuilder app)
{
var factory = InMemoryFactory.Create(
scopes: Scopes.Get(),
clients: Clients.Get(),
users: new List<InMemoryUser>());
var options = new IdentityServerOptions
{
Factory = factory
};
app.UseIdentityServer(options);
}}
Ø 托管IdentityServer
最后一步是主機IdentityServer。 為此我們將武士刀自托管包添加到控制台應用程序:
install-package Microsoft.Owin.SelfHost
添加以下代碼Program.cs:
using Microsoft.Owin.Hosting;using Thinktecture.IdentityServer.Core.Logging;
static void Main(string[] args){
LogProvider.SetCurrentLogProvider(new DiagnosticsTraceLogProvider());
using (WebApp.Start<Startup>("https://localhost:44333"))
{
Console.WriteLine("server running...");
Console.ReadLine();
}}
當您運行控制台應用程序,您應該看到一些診斷輸出server running...。
v 添加一個API
在這一部分,我們將添加一個簡單的web API,它被配置為從IdentityServer我們只是需要一個訪問令牌。
Ø 創建網絡主機
添加一個新的ASP.NET Web Application解決方案和選擇Empty選項(沒有框架的引用)。
添加必要的nuget包:
install-package Microsoft.Owin.Host.SystemWeb
install-package Microsoft.AspNet.WebApi.Owin
install-package Thinktecture.IdentityServer3.AccessTokenValidation
Ø 添加一個控制器
添加這個簡單的測試控制器:
[Route("test")]public class TestController : ApiController{
public IHttpActionResult Get()
{
var caller = User as ClaimsPrincipal;
return Json(new
{
message = "OK computer",
client = caller.FindFirst("client_id").Value
});
}}
的User財產的控制器給你訪問的訪問令牌。
Ø 添加啟動
添加以下Startup類設置web api和配置與IdentityServer信任
using Thinktecture.IdentityServer.AccessTokenValidation;
public void Configuration(IAppBuilder app){
// accept access tokens from identityserver and require a scope of 'api1'
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://localhost:44333",
RequiredScopes = new[] { "api1" }
});
// configure web api
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
// require authentication for all controllers
config.Filters.Add(new AuthorizeAttribute());
app.UseWebApi(config);}
試着打開瀏覽器並訪問測試控制器,您應該看到一個401因為必要的訪問令牌是失蹤。
v 添加一個控制台客戶
在接下來的部分,我們將添加一個簡單的控制台客戶端請求一個訪問令牌和使用進行身份驗證的api。
首先添加一個新的控制台項目和安裝nuget包OAuth2客戶機助手庫:
install-package Thinktecture.IdentityModel.Client
第一個代碼片段使用客戶端證書請求訪問令牌:
using Thinktecture.IdentityModel.Client;
static TokenResponse GetToken(){
var client = new OAuth2Client(
new Uri("https://localhost:44333/connect/token"),
"silicon",
"F621F470-9731-4A25-80EF-67A6F7C5F4B8");
return client.RequestClientCredentialsAsync("api1").Result;}
第二個代碼段調用API使用訪問令牌:
using Thinktecture.IdentityModel.Client;
static void CallApi(TokenResponse response){
var client = new HttpClient();
client.SetBearerToken(response.AccessToken);
Console.WriteLine(client.GetStringAsync("http://localhost:14869/test").Result);}
如果你叫兩個片段,您應該看到{"message":"OK computer","client":"silicon"}在您的控制台。
v 添加一個用戶
到目前為止,客戶端請求的訪問令牌本身,沒有用戶。 讓我們介紹一個人。
Ø 添加一個用戶服務
用戶服務管理用戶,對於此示例,我們將使用簡單的內存的用戶服務。 首先我們需要定義一些用戶:
using Thinktecture.IdentityServer.Core.Services.InMemory;
static class Users{
public static List<InMemoryUser> Get()
{
return new List<InMemoryUser>
{
new InMemoryUser
{
Username = "bob",
Password = "secret",
Subject = "1"
},
new InMemoryUser
{
Username = "alice",
Password = "secret",
Subject = "2"
}
};
}}
Username和Password用於驗證用戶, 的Subject是該用戶的唯一標識符,將嵌入到訪問令牌。
在Startup配置方法取代所說空的用戶列表Get方法。
替換:csharp users: new List<InMemoryUser>()); :csharp users: Users.Get());
Ø 添加一個客戶
接下來,我們將添加一個客戶端定義使用流resource owner password credential grant。 這個流允許客戶端用戶的用戶名和密碼發送到令牌服務,得到一個訪問令牌。
在總Clients類是這樣的:
using Thinktecture.IdentityServer.Core.Models;
static class Clients{
public static List<Client> Get()
{
return new List<Client>
{
// no human involved
new Client
{
ClientName = "Silicon-only Client",
ClientId = "silicon",
Enabled = true,
AccessTokenType = AccessTokenType.Reference,
Flow = Flows.ClientCredentials,
ClientSecrets = new List<ClientSecret>
{
new ClientSecret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())
}
},
// human is involved
new Client
{
ClientName = "Silicon on behalf of Carbon Client",
ClientId = "carbon",
Enabled = true,
AccessTokenType = AccessTokenType.Reference,
Flow = Flows.ResourceOwner,
ClientSecrets = new List<ClientSecret>
{
new ClientSecret("21B5F798-BE55-42BC-8AA8-0025B903DC3B".Sha256())
}
}
};
}}
Ø 更新的API
當一個人類,將包含訪問令牌sub惟一標識用戶。 讓我們把這個小修改API控制器:
[Route("test")]public class TestController : ApiController{
public IHttpActionResult Get()
{
var caller = User as ClaimsPrincipal;
var subjectClaim = caller.FindFirst("sub");
if (subjectClaim != null)
{
return Json(new
{
message = "OK user",
client = caller.FindFirst("client_id").Value,
subject = subjectClaim.Value
});
}
else
{
return Json(new
{
message = "OK computer",
client = caller.FindFirst("client_id").Value
});
}
}}
Ø 更新客戶端
下添加一個新的方法給客戶端請求一個訪問令牌代表用戶:
static TokenResponse GetUserToken(){
var client = new OAuth2Client(
new Uri("https://localhost:44333/connect/token"),
"carbon",
"21B5F798-BE55-42BC-8AA8-0025B903DC3B");
return client.RequestResourceOwnerPasswordAsync("bob", "secret", "api1").Result;}
現在嘗試兩種方法的請求令牌和檢查要求和API的回應。
該項目名稱為Simplest OAuth2 Walkthrough。
v 下一步要做什么
這演練了一個非常簡單的OAuth2場景。 下一個你可以試試:
l 其他流,如隱式、代碼或混合。 他們都是推動者等高級場景聯合會和外部的身份
l 連接到您的用戶數據庫,通過編寫自己的用戶服務或使用我們的開箱即用的支持ASP.Net Identity和MembershipReboot
l 客戶端和范圍配置存儲在一個數據存儲。 我們有現成的實體框架支持。
l 使用OpenID連接和添加身份驗證和身份令牌標識范圍
l 本教程將引導您完成必要的步驟來得到一個最小IdentityServer啟動並運行。 為簡單起見,我們將主機IdentityServer和客戶端在同一web應用程序,這可能不是一個非常現實的場景中,但可以讓你開始沒有使它太復雜。
可以找到完整的源代碼在這里。
v 第1部分- MVC身份驗證和授權
在第一部分,我們將創建一個簡單的MVC應用程序並通過IdentityServer添加身份驗證。 然后我們會仔細看看Claims,Claims轉換和授權
Ø 創建web應用程序
在Visual Studio 2013中,創建一個標准的MVC應用程序和身份驗證設置為“無身份驗證”。
現在您可以切換項目SSL使用屬性窗口:
重要的別忘了更新在您的項目中開始URL屬性。
Ø 添加IdentityServer
IdentityServer基於OWIN /刀和分布式Nuget包。 將其添加到新創建的web主機,安裝以下兩個方案:
install-package Microsoft.Owin.Host.Systemweb
install-package Thinktecture.IdentityServer3
Ø 配置IdentityServer -客戶
IdentityServer需要一些關於客戶的信息支持,這可以簡單地提供使用Client對象:
public static class Clients{
public static IEnumerable<Client> Get()
{
return new[]
{
new Client
{
Enabled = true,
ClientName = "MVC Client",
ClientId = "mvc",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://localhost:44319/"
}
}
};
}}
Ø 配置IdentityServer——用戶
接下來,我們將添加一些用戶再次IdentityServer——這可以通過提供一個簡單的c#類。 你可以從任何數據存儲和檢索用戶信息我們提供開箱即用的支持ASP。 網絡身份和MembershipReboot。
public static class Users{
public static List<InMemoryUser> Get()
{
return new List<InMemoryUser>
{
new InMemoryUser
{
Username = "bob",
Password = "secret",
Subject = "1",
Claims = new[]
{
new Claim(Constants.ClaimTypes.GivenName, "Bob"),
new Claim(Constants.ClaimTypes.FamilyName, "Smith")
}
}
};
}}
Ø 添加啟動
IdentityServer在啟動配置類。 這里我們提供關於客戶的信息,用戶,范圍, 簽名證書和其他一些配置選項。 在生產中應該從Windows證書存儲加載簽名證書或其他擔保來源。 在這個示例中,我們簡單地添加它到項目文件(您可以下載測試證書在這里。 將其添加到項目並設置其構建行動Copy to output。
對信息如何加載證書從Azure網站看到在這里。
public class Startup{
public void Configuration(IAppBuilder app)
{
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "Embedded IdentityServer",
SigningCertificate = LoadCertificate(),
Factory = InMemoryFactory.Create(
users : Users.Get(),
clients: Clients.Get(),
scopes : StandardScopes.All)
});
});
}
X509Certificate2 LoadCertificate()
{
return new X509Certificate2(
string.Format(@"{0}\bin\identityServer\idsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test");
}}
在這一點上你有一個功能齊全的IdentityServer你可以瀏覽發現端點檢查配置:
Ø RAMMFAR
最后一件事,請不要忘了RAMMFAR添加到您的網站。 配置,否則我們的一些嵌入式資產由IIS將不能正確加載:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" /></system.webServer>
v 添加和配置OpenID身份驗證連接中間件
OIDC驗證添加到MVC應用程序中,我們需要添加兩個包:
install-package Microsoft.Owin.Security.Cookies
install-package Microsoft.Owin.Security.OpenIdConnect
在啟動配置餅干中間件。 cs的默認值:
install-package Microsoft.Owin.Security.Cookies
install-package Microsoft.Owin.Security.OpenIdConnect
在啟動配置餅干中間件。 cs的默認值: 配置,否則我們的一些嵌入式資產由IIS將不能正確加載:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
點OpenID中間件(也在StartUp.cs)連接到我們的嵌入式版本的IdentityServer和使用先前配置的客戶端配置:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
ClientId = "mvc",
RedirectUri = "https://localhost:44319/",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies"
});
v 添加一個受保護的資源和Claims
啟動認證與IdentityServer您需要創建一個受保護的資源,如通過增加全球授權過濾器。 對於我們的示例,我們將簡單地保護About行動上的Home控制器。 此外我們將交出聲稱視圖中我們可以看到號稱IdentityServer發出的有:
[Authorize]public ActionResult About(){
return View((User as ClaimsPrincipal).Claims);}
相應的觀點是這樣的:
@model IEnumerable<System.Security.Claims.Claim>
<dl>
@foreach (var claim in Model)
{
<dt>@claim.Type</dt>
<dd>@claim.Value</dd>
}</dl>
Ø 身份驗證和Claims
點擊鏈接將觸發身份驗證。 IdentityServer將顯示登錄屏幕並發送一個令牌回主應用程序。 OpenID Connect中間件驗證令牌,提取並將其傳送給Cookies中間件,這將反過來設置身份驗證cookie。 用戶現在簽署。
Ø 添加角色和范圍
在下一步我們要添加一些聲稱我們的用戶角色,稍后我們將使用授權。
現在我們得到了OIDC標准范圍,讓我們定義一個角色范圍,包括角色要求並添加到標准范圍:
public static class Scopes{
public static IEnumerable<Scope> Get()
{
var scopes = new List<Scope>
{
new Scope
{
Enabled = true,
Name = "roles",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}
}
};
scopes.AddRange(StandardScopes.All);
return scopes;
}}
也改變了工廠Startup
Factory = InMemoryFactory.Create(
users: Users.Get(),
clients: Clients.Get(),
scopes: Scopes.Get())
接下來,我們添加兩個角色聲稱鮑勃:
public static class Users{
public static IEnumerable<InMemoryUser> Get()
{
return new[]
{
new InMemoryUser
{
Username = "bob",
Password = "secret",
Subject = "1",
Claims = new[]
{
new Claim(Constants.ClaimTypes.GivenName, "Bob"),
new Claim(Constants.ClaimTypes.FamilyName, "Smith"),
new Claim(Constants.ClaimTypes.Role, "Geek"),
new Claim(Constants.ClaimTypes.Role, "Foo")
}
}
};
}}
Ø 改變了中間件配置要求的角色
默認情況下,OIDC中間件要求兩個范圍:openid和profile——這就是為什么IdentityServer包括Claims主體和名稱。 現在我們添加一個請求roles范圍:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
ClientId = "mvc",
Scope = "openid profile roles",
RedirectUri = "https://localhost:44319/",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies"
});
成功的身份驗證之后,現在您應該看到角色收集Claims在用戶的Claims:
Ø 要求轉換
檢查聲明這個頁面時,您將注意到兩件事:一些聲稱奇怪的長類型名稱和有更多的比你可能需要在您的應用程序。
長的聲明名稱來自微軟的JWT處理程序試圖一些Claims類型映射到.net的ClaimTypes類類型。 你可以關掉這個行為與以下代碼行(Startup)。
這也意味着你需要調整配置anti-CSRF保護新的獨特sub申請類型:
AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject;JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
聲稱將現在看起來像這樣:
這是一個進步,但是仍有一些低水平協議聲稱,當然是不需要通過典型的業務邏輯。 將原始輸入Claims轉化為特定於應用程序的過程Claims稱為Claims轉換。 在這個過程中你把傳入的說法,決定你想要號稱也許需要聯系其他數據存儲檢索更聲稱所需的應用程序。
OIDC中間件有通知,您可以使用它們來做Claims轉型——由此產生的Claims將存儲在cookie:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
ClientId = "mvc",
Scope = "openid profile roles",
RedirectUri = "https://localhost:44319/",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
var id = n.AuthenticationTicket.Identity;
// we want to keep first name, last name, subject and roles
var givenName = id.FindFirst(Constants.ClaimTypes.GivenName);
var familyName = id.FindFirst(Constants.ClaimTypes.FamilyName);
var sub = id.FindFirst(Constants.ClaimTypes.Subject);
var roles = id.FindAll(Constants.ClaimTypes.Role);
// create new identity and set name and role claim type
var nid = new ClaimsIdentity(
id.AuthenticationType,
Constants.ClaimTypes.GivenName,
Constants.ClaimTypes.Role);
nid.AddClaim(givenName);
nid.AddClaim(familyName);
nid.AddClaim(sub);
nid.AddClaims(roles);
// add some other app specific claim
nid.AddClaim(new Claim("app_specific", "some data"));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
}
}
});
添加上面的代碼之后,我們要求的設置現在看起來像這樣:
Ø 授權
現在我們已經認證和一些Claims,我們可以開始添加簡單的授權規則。
MVC有一個內置的屬性[Authorize]需要通過身份驗證的用戶,您還可以使用此屬性來標注角色從屬關系的要求。 我們不推薦這種方法,因為這通常會導致代碼混合業務/控制器邏輯和授權策略的擔憂。 我們不推薦從控制器分離授權邏輯導致清潔代碼和更好的可測試性(閱讀更多在這里)。
Ø 資源授權
添加新授權的基礎設施和新屬性,我們添加一個Nuget包:
install-package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc
接下來我們注釋Contact行動上的Home控制器和一個屬性,表示這一行動將執行Read的ContactDetails資源:
[ResourceAuthorize("Read", "ContactDetails")]public ActionResult Contact(){
ViewBag.Message = "Your contact page.";
return View();}
注意,屬性不表示允許讀取聯系人是誰——我們邏輯移到一個單獨的授權經理知道行動,資源和誰可以做哪個操作在你的應用程序:
public class AuthorizationManager : ResourceAuthorizationManager{
public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
{
switch (context.Resource.First().Value)
{
case "ContactDetails":
return AuthorizeContactDetails(context);
default:
return Nok();
}
}
private Task<bool> AuthorizeContactDetails(ResourceAuthorizationContext context)
{
switch (context.Action.First().Value)
{
case "Read":
return Eval(context.Principal.HasClaim("role", "Geek"));
case "Write":
return Eval(context.Principal.HasClaim("role", "Operator"));
default:
return Nok();
}
}}
最后我們授權管理器連接到OWIN管道Startup:
app.UseResourceAuthorization(new AuthorizationManager());
運行示例和步驟通過代碼來熟悉流。
Ø 角色權限
然而,如果你選擇使用[Authorize(Roles = "Foo,Bar")]要知道網站可以被扔進一個無限重定向循環當當前用戶身份驗證,但不屬於其中的一個角色或用戶進入Authorize在MVC 5.2屬性(驗證)。 這是因為不良的結果Authorize屬性將行動的結果是401年未授權用戶身份驗證,而不是一個的角色。 401結果觸發重定向與IdentityServer進行身份驗證,驗證,然后將用戶重定向回,然后重定向循環開始。 這種行為可以克服通過重寫Authorize屬性的HandleUnauthorizedRequest方法如下,然后使用自定義授權屬性相反的MVC。
// Customized authorization attribute:public class AuthAttribute : AuthorizeAttribute{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// 403 we know who you are, but you haven't been granted access
filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Forbidden);
}
else
{
// 401 who are you? go login and then try again
filterContext.Result = new HttpUnauthorizedResult();
}
}}
// Usage:[Auth(Roles = "Geek")]public ActionResult About(){
// ...}
Ø 更多的授權和處理拒絕訪問場景
讓我們做更多授權通過添加一個新的操作方法Home控制器
[ResourceAuthorize("Write", "ContactDetails")]public ActionResult UpdateContact(){
ViewBag.Message = "Update your contact details!";
return View();}
當你試圖調用,導航到采取行動/home/updatecontact您將看到一個URLforbidden錯誤頁面。
事實上你會看到不同的響應基於如果用戶已經通過身份驗證。 如果不是MVC將重定向到登錄頁面,如果身份驗證,您將看到禁止響應。 這是由設計(閱讀更多在這里)。
你可以通過檢查處理被禁止的條件403狀態碼,我們提供這樣一個開箱即用的過濾:
[ResourceAuthorize("Write", "ContactDetails")][HandleForbidden]public ActionResult UpdateContact(){
ViewBag.Message = "Update your contact details!";
return View();}
的HandleForbidden過濾器(當然也可以全球)將重定向到指定的視圖時默認403得到了釋放,我們尋找一個視圖Forbidden。
您還可以使用授權經理命令式地,給你更多的選擇:
[HandleForbidden]public ActionResult UpdateContact(){
if (!HttpContext.CheckAccess("Write", "ContactDetails", "some more data"))
{
// either 401 or 403 based on authentication state
return this.AccessDenied();
}
ViewBag.Message = "Update your contact details!";
return View();}
Ø 添加注銷
添加注銷很容易,只需添加一個新的操作調用Signout方法在武士刀的身份驗證管理器:
public ActionResult Logout(){
Request.GetOwinContext().Authentication.SignOut();
return Redirect("/");}
這將啟動所謂的往返endsessionIdentityServer端點。 這個端點將清晰的身份驗證cookie和終止會話:
通常最安全的事情現在會簡單地關閉瀏覽器窗口擺脫所有的會話數據。 一些應用程序雖然想給用戶一個機會返回一個匿名用戶。
這是可能的,但需要一些步驟,首先需要注冊一個有效的URL注銷手續完成后返回。 這樣做是在客戶端定義MVC應用程序(注意新PostLogoutRedirectUris設置):
new Client {
Enabled = true,
ClientName = "MVC Client",
ClientId = "mvc",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://localhost:44319/"
},
PostLogoutRedirectUris = new List<string>
{
"https://localhost:44319/"
}}
下一個客戶端必須證明其身份注銷端點,以確保我們重定向到正確的URL(而不是一些垃圾信息散布者/釣魚頁面)。 這是通過發送回最初的身份令牌,客戶端身份驗證過程中收到了。 到目前為止,我們已經丟棄這個令牌,現在是時候改變轉換邏輯來保護它。
這是通過將這行代碼添加到我們的SecurityTokenValidated
// keep the id_token for logoutnid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
最后一步,我們必須把id_token當用戶退出系統時,我們讓IdentityServer往返。 這也是使用通知OIDC中間件:
RedirectToIdentityProvider = async n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token").Value;
n.ProtocolMessage.IdTokenHint = idTokenHint;
}
}
這些變化,IdentityServer會給用戶一個鏈接返回到調用應用程序:
Ø 添加谷歌身份驗證
接下來,我們想啟用外部身份驗證。 這是通過添加額外的武士刀認證中間件IdentityServer——在我們的例子中,我們將使用谷歌。
注冊IdentityServer與谷歌
首先我們需要注冊IdentityServer在谷歌的開發者控制台。 這包括幾個步驟。
首先導航到:
https://console.developers.google.com
l 創建一個新項目
l 使Google + API
l 同意屏幕配置電子郵件地址和產品名稱
l 創建一個客戶端應用程序
在您創建客戶端應用程序,開發人員控制台將顯示您客戶id和一個客戶的秘密。 我們需要這兩個值后,我們配置谷歌中間件。
添加谷歌身份驗證中間件
添加中間件通過安裝以下方案:
install-package Microsoft.Owin.Security.Google
配置中間件
添加下面的方法Startup:
private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType){
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
AuthenticationType = "Google",
Caption = "Sign-in with Google",
SignInAsAuthenticationType = signInAsType,
ClientId = "...",
ClientSecret = "..."
});}
private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType){
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
AuthenticationType = "Google",
Caption = "Sign-in with Google",
SignInAsAuthenticationType = signInAsType,
ClientId = "...",
ClientSecret = "..."
});}
接下來我們點IdentityServer選項類這個方法:
idsrvApp.UseIdentityServer(new IdentityServerOptions{
SiteName = "Embedded IdentityServer",
SigningCertificate = LoadCertificate(),
Factory = InMemoryFactory.Create(
users: Users.Get(),
clients: Clients.Get(),
scopes: Scopes.Get()),
AuthenticationOptions = new Thinktecture.IdentityServer.Core.Configuration.AuthenticationOptions
{
IdentityProviders = ConfigureIdentityProviders
}});
就是這樣! 用戶下次登錄時,會有一個登錄頁面上的“與谷歌登錄”按鈕:
請注意,role與谷歌聲稱丟失時登錄。 很有意義,因為谷歌沒有角色的概念。 做好准備,並非所有的身份提供者將提供相同的聲明類型。
v 第2部分-添加和調用Web API
在這部分我們將添加一個Web API的解決方案。 API將由IdentityServer擔保。 接下來我們的MVC應用程序將調用API使用信任子系統和身份代表團的方法。
Ø 添加Web API項目
最簡單的方法創建一個干凈的API項目是通過添加一個空的web項目。
接下來,我們將添加Web API和武士刀使用Nuget托管:
install-package Microsoft.Owin.Host.SystemWeb
install-package Microsoft.Aspnet.WebApi.Owin
Ø 添加一個測試控制器
下面的控制器將返回所有Claims回調用者——這將使我們能夠檢查將發送到API的令牌。
[Route("identity")][Authorize]public class IdentityController : ApiController{
public IHttpActionResult Get()
{
var user = User as ClaimsPrincipal;
var claims = from c in user.Claims
select new
{
type = c.Type,
value = c.Value
};
return Json(claims);
}}
Ø 連接在啟動Web API和安全
一如既往地Katana-based托管,發生在所有配置Startup:
public class Startup{
public void Configuration(IAppBuilder app)
{
// web api configuration
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}}
另外我們想確保我們的API使用IdentityServer——需要兩件事:
l 只接受IdentityServer發行的令牌
l 只接受令牌,發布了,我們會給我們的API——API的名稱sampleApi(也稱為scope)
完成,我們添加一個Nuget包:
install-package Thinktecture.IdentityServer3.AccessTokenValidation
. . 並使用它們Startup:
public class Startup{
public void Configuration(IAppBuilder app)
{
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
RequiredScopes = new[] { "sampleApi" }
});
// web api configuration
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}}
請注意IdentityServer問題標准JSON Web標記(JWT),你可以使用普通的武士刀JWT中間件來驗證它們。 我們的中間件只是一個方便因為它可以自動配置本身使用IdentityServer發現文檔(元數據)。
Ø 注冊在IdentityServer API
接下來我們需要注冊的API——這是通過擴展范圍。 這一次我們添加一個所謂的資源范圍:
public static class Scopes{
public static IEnumerable<Scope> Get()
{
var scopes = new List<Scope>
{
new Scope
{
Enabled = true,
Name = "roles",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}
},
new Scope
{
Enabled = true,
Name = "sampleApi",
Description = "Access to a sample API",
Type = ScopeType.Resource
}
};
scopes.AddRange(StandardScopes.All);
return scopes;
}}
Ø 注冊一個Web API客戶端
接下來我們將調用API。 你可以為使用客戶端憑據(如服務帳戶)或通過授權用戶的身份。 我們將開始與客戶憑證。
首先我們需要注冊一個新客戶的MVC應用程序。出於安全原因,IdentityServer只允許每個客戶一個流, 因為我們現有MVC客戶已經使用隱式流程,我們需要創建一個新的客戶服務的服務通信。
public static class Clients{
public static IEnumerable<Client> Get()
{
return new[]
{
new Client
{
Enabled = true,
ClientName = "MVC Client",
ClientId = "mvc",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://localhost:44319/"
}
},
new Client
{
Enabled = true,
ClientName = "MVC Client (service communication)",
ClientId = "mvc_service",
ClientSecrets = new List<ClientSecret>
{
new ClientSecret("secret".Sha256())
},
Flow = Flows.ClientCredentials
}
};
}}
Ø 調用API
調用API包含兩個部分:
l 請求令牌從IdentityServer API使用客戶端證書
l 調用API使用訪問令牌
簡化與OAuth2令牌的交互端點,添加客戶端包通過Nuget MVC項目:
install-package Thinktecture.IdentityModel.Client
在控制器中,添加新類CallApiController。 下面的代碼片段的令牌的請求sampleApi
private async Task<TokenResponse> GetTokenAsync(){
var client = new OAuth2Client(
new Uri("https://localhost:44319/identity/connect/token"),
"mvc_service",
"secret");
return await client.RequestClientCredentialsAsync("sampleApi");}
private async Task<TokenResponse> GetTokenAsync(){
var client = new OAuth2Client(
new Uri("https://localhost:44319/identity/connect/token"),
"mvc_service",
"secret");
return await client.RequestClientCredentialsAsync("sampleApi");}
而以下代碼片段調用我們的身份端點使用請求的訪問令牌:
private async Task<string> CallApi(string token){
var client = new HttpClient();
client.SetBearerToken(token);
var json = await client.GetStringAsync("https://localhost:44321/identity");
return JArray.Parse(json).ToString();}
把所有在一起,新添加的控制器調用服務並顯示生成的聲稱在一個視圖:
public class CallApiController : Controller{
// GET: CallApi/ClientCredentials
public async Task<ActionResult> ClientCredentials()
{
var response = await GetTokenAsync();
var result = await CallApi(response.AccessToken);
ViewBag.Json = result;
return View("ShowApiResult");
}
// helpers omitted}
public class CallApiController : Controller{
// GET: CallApi/ClientCredentials
public async Task<ActionResult> ClientCredentials()
{
var response = await GetTokenAsync();
var result = await CallApi(response.AccessToken);
ViewBag.Json = result;
return View("ShowApiResult");
}
// helpers omitted}
結果是這樣的:
換句話說- API知道調用者:
l 發行人名稱、觀眾和過期(使用的令牌驗證中間件)
l 令牌的范圍(范圍驗證使用的中間件)發布
l 客戶機id
所有Claims的令牌將變成一個ClaimsPrincipal和通過.User控制器上的屬性。
Ø 代表用戶調用的API
接下來我們要調用API使用用戶的身份。 這是通過添加完成sampleApi范圍的名單范圍的OpenID連接中間件配置。 我們還需要表明我們想請求一個訪問令牌通過改變反應類型:
Scope = "openid profile roles sampleApi",ResponseType = "id_token token"
盡快的響應類型token請求IdentityServer停止,包括Claims的身份令牌。 這是優化的目的,因為你現在有一個訪問令牌,允許從用戶信息檢索的端點,同時保持身份令牌小。
訪問端點並不難——用戶信息UserInfoClient類可以使它更簡單。 除了我們現在也將訪問令牌存儲在cookie,所以我們可以使用它當我們想訪問API代表用戶:
SecurityTokenValidated = async n =>
{
var nid = new ClaimsIdentity(
n.AuthenticationTicket.Identity.AuthenticationType,
Constants.ClaimTypes.GivenName,
Constants.ClaimTypes.Role);
// get userinfo data
var userInfoClient = new UserInfoClient(
new Uri(n.Options.Authority + "/connect/userinfo"),
n.ProtocolMessage.AccessToken);
var userInfo = await userInfoClient.GetAsync();
userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Item1, ui.Item2)));
// keep the id_token for logout
nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
// add access token for sample API
nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
// keep track of access token expiration
nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));
// add some other app specific claim
nid.AddClaim(new Claim("app_specific", "some data"));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
}
另一個選擇是重新配置IdentityServer並設置的范圍AlwaysIncludeInIdToken國旗聲稱力范圍包含聲稱的身份令牌,我把它留給讀者作為練習。
調用API
由於訪問令牌現在存儲在cookie中,我們可以簡單地從Claims本金和用它來檢索它調用服務:
// GET: CallApi/UserCredentialspublic async Task<ActionResult> UserCredentials(){
var user = User as ClaimsPrincipal;
var token = user.FindFirst("access_token").Value;
var result = await CallApi(token);
ViewBag.Json = result;
return View("ShowApiResult");}
在結果頁面上,您現在可以看到subClaims包括在內,這意味着API現在工作代表一個用戶:
如果你現在添加范圍要求role到sampleApi范圍——用戶的角色將被包括在訪問令牌:
new Scope{
Enabled = true,
Name = "sampleApi",
Description = "Access to a sample API",
Type = ScopeType.Resource,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}}
新 ScopeClaim(“角色”)
}}
第四章配置
v 概述
IdentityServer3打包為中間件和使用典型的“選項”模式配置:
public void Configuration(IAppBuilder appBuilder){
var options = new IdentityServerOptions
{
SigningCertificate = Certificate.Get(),
Factory = factory,
};
appBuilder.UseIdentityServer(options);}
的IdentityServerOptionsIdentityServer類包含所有配置。 一部分由發行人的簡單屬性名稱或網站標題,您可以從任何你認為合適的來源(靜態代碼中,配置文件或數據庫)。 另一部分是所謂的服務工廠充當注冊IdentityServer內部處理的某些方面。
托管在IIS和RAMMFAR
網頁提供的文件作為嵌入式IdentityServer議會內部的資產。 當在IIS托管或IIS Express允許這些文件送達RAMMFAR(runAllManagedModulesForAllRequests)需要在web . config中啟用:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
看到樣品
v IdentityServer選項
的IdentityServerOptions 類的頂層容器IdentityServer的所有配置設置。
- IssuerUri
- 唯一的名稱服務器實例,如https://myissuer.com。 默認為IdentityServer安裝的基URL
- SiteName
- 網站的顯示名稱中使用標准的觀點。
- SigningCertificate
- X。 509證書(和相應的私鑰)簽署安全令牌。
- SecondarySigningCertificate
- 二級證書,會發現文檔。 可用於客戶准備證書翻轉。
- RequireSsl
- 表明如果SSL IdentityServer所需。 默認為true。
- PublicOrigin
- 默認情況下,IdentityServer使用主機、協議和端口從HTTP請求在創建鏈接。 這可能不是准確在反向代理或負載平衡情況。 你可以覆蓋原點用於鏈接生成使用這個屬性。
- Endpoints
- 允許啟用或禁用特定的端點(默認情況下所有端點是啟用)。
- Factory(必需)
- DataProtector
- 自定義數據集的保護者。 在默認情況下使用武士刀主機數據保護。
- AuthenticationOptions
- PluginConfiguration
- 允許添加協議插件如ws - federation支持。
- CorsPolicy
- 配置CORS
- CspOptions
- 配置CSP
- ProtocolLogoutUrls
- 配置回調url應該被稱為在注銷(主要用於協議插件)。
- LoggingOptions
- 相關的配置設置日志記錄
- EventsOptions
- 相關的配置設置事件
- EnableWelcomePage
- 啟用或禁用默認的歡迎頁面。 默認為true。
v 服務工廠
IdentityServer3包含許多功能實現OpenID和OAuth2連接。 許多這些功能設計,這樣他們就可以被取代。 這將是有用的場景缺省邏輯不匹配托管應用程序的需求,或者只是應用程序希望提供一個完全不同的實現。 事實上,有些在IdentityServer3擴展點,需要提供的托管應用程序(如存儲配置數據或驗證的身份管理實現用戶的憑證)。
的Thinktecture.IdentityServer.Core.Configuration.IdentityServerServiceFactory擁有所有這些構建塊,必須提供在啟動時使用IdentityServerOptions類(見在這里有關配置選項的更多信息)。
擴展點分為三類。
v 強制性的
- UserService
- 實現用戶身份驗證對本地用戶存儲、外部用戶協會聲稱經過檢索和邏輯。 有兩個標准的實現MembershipReboot和ASP.NET Identity
- ScopeStore
- 實現檢索范圍配置數據
- ClientStore
- 實現客戶端配置數據的檢索
的InMemoryFactory允許設置一個服務工廠通過為用戶提供內存存儲,客戶和范圍(見在這里)。
v 強制性的生產場景(但默認內存中實現)
- AuthorizationCodeStore
- 實現存儲和檢索的授權碼(接口)
- TokenHandleStore
- 實現存儲和檢索的處理令牌(供參考接口)
- RefreshTokenStore
- 實現存儲和檢索的刷新令牌(接口)
- ConsentStore
- 實現存儲和檢索的同意決定(接口)
- ViewService
- 實現檢索界面的資產。 默認使用嵌入的資產。 (接口)
- TokenService
- 實現創建身份和訪問令牌(接口)
- ClaimsProvider
- 實現檢索申請身份和訪問令牌(接口)
- TokenSigningService
- 實現創建和簽署安全令牌(接口)
- CustomGrantValidator
- 實現自定義的驗證授權類型(接口)
- CustomRequestValidator
- 實現自定義額外的授權和驗證令牌請求(接口)
- RefreshTokenService
- 實現創建和更新刷新令牌(接口)
- ExternalClaimsFilter
- 實現過濾和轉換申請外部身份提供者(接口)
- CustomTokenValidator
- 實現自定義令牌的其他驗證令牌驗證端點(接口)
- ConsentService
- 實現邏輯同意的決定(接口)
- ClientPermissionsService
- 實現了檢索和撤銷批准,引用和刷新令牌(接口)
- EventService
- 實現將事件轉發給一些日志記錄系統(如彈性搜索)(接口)
- RedirectUriValidator
- 實現驗證重定向和注銷后uri(接口)
- LocalizationService
- 實現顯示的本地化字符串(接口)
- ClientSecretValidator
- 實現驗證客戶的秘密(接口)
- CorsPolicyService
- 實現了歌珥政策(接口)
v 可選(可以更換,但有默認的實現)
看到在這里有關注冊定制服務的更多信息和存儲的實現。
v 內存中的工廠
內存廠是一個簡單的方法來得到一個測試/ dev版本IdentityServer啟動並運行。
當你創建in-mem工廠你可以提供一個靜態列表Client, Scope和InMemoryUser。 所有其他數據(e。 g同意,刷新令牌,引用標記,代碼等等)將只保存在內存中。 這只是適合測試和開發。
var factory = InMemoryFactory.Create(
users: Users.Get(),
clients: Clients.Get(),
scopes: Scopes.Get());
var idsrvOptions = new IdentityServerOptions{
Factory = factory,
SigningCertificate = Cert.Load(),};
app.UseIdentityServer(idsrvOptions);
第五章客戶
的Client類模型OpenID連接或OAuth2客戶機——例如一個本地應用程序中,web應用程序或者JS-based應用程序(鏈接)。
- Enabled
- 指定是否啟用客戶機。 默認為true。
- ClientId
- 惟一的ID的客戶端
- ClientSecrets
- 列表,客戶需要一個秘密的秘密,只有相關的流
- ClientName
- 客戶端顯示名稱(用於日志記錄和同意屏幕)
- ClientUri
- URI進一步信息客戶端(同意屏幕上使用)
- LogoUri
- URI端標志(同意屏幕上使用)
- RequireConsent
- 指定是否需要同意屏幕。 默認為true。
- AllowRememberConsent
- 指定用戶可以選擇存儲是否同意的決定。 默認為true。
- Flow
- 指定允許客戶機(流AuthorizationCode, Implicit, Hybrid, ResourceOwner,ClientCredentials或Custom)。 默認為Implicit。
- AllowClientCredentialsOnly
- 獲取或設置一個值指示是否允許該客戶端請求令牌只使用客戶端證書。 這是很有用的,例如,你想要一個客戶機能夠使用一個以用戶為中心流隱式和另外客戶端憑證流。 默認值為false。 應該只用於機密客戶(如不隱式)。
- RedirectUris
- 指定允許的uri返回標記或授權代碼
- PostLogoutRedirectUris
- 注銷后重定向到指定允許的uri
- ScopeRestrictions
- 指定范圍,允許客戶端請求。 如果空,客戶端可以請求作用域。 默認為空集合。
- IdentityTokenLifetime
- 一生的身份令牌在幾秒鍾內(默認為300秒/ 5分鍾)
- AccessTokenLifetime
- 一生的訪問令牌在幾秒鍾內(默認為3600秒/ 1小時)
- AuthorizationCodeLifetime
- 一生的授權代碼秒(默認為300秒/ 5分鍾)
- AbsoluteRefreshTokenLifetime
- 一生最大的刷新令牌在幾秒鍾內。 默認為2592000秒/ 30天
- SlidingRefreshTokenLifetime
- 滑動的一生秒刷新令牌。 默認為1296000秒/ 15天
- RefreshTokenUsage
- ReUse:刷新令牌處理刷新令牌時將保持不變
- OneTime:刷新令牌處理刷新令牌時將被更新
- RefreshTokenExpiration
- Absolute:刷新令牌將到期在一個固定的時間點(AbsoluteRefreshTokenLifetime指定的)
- Sliding:當刷新令牌,將再次刷新令牌的生命周期(通過SlidingRefreshTokenLifetime中指定的數量)。 一生不會超過AbsoluteRefreshTokenLifetime。
- AccessTokenType
- 指定是否訪問令牌是一個參考標記或自包含JWT令牌(默認Jwt)。
- EnableLocalLogin
- 指定如果這個客戶端可以使用本地帳戶,或外部國內流離失所者。 默認為true。
- IdentityProviderRestrictions
- 指定與該客戶端可以使用外部的國內流離失所者(如果允許列表為空所有國內流離失所者)。 默認為空。
- IncludeJwtId
- 指定JWT訪問令牌是否應該有一個嵌入式惟一的ID(通過jtiClaims)。
- Claims
- 允許設置申請客戶端(將包括在訪問令牌)。
- AlwaysSendClientClaims
- 如果設置,客戶聲稱將發送每流。 如果沒有,只有客戶端憑證流(默認false)
- PrefixClientClaims
- 如果設置,所有客戶端將前綴client_確保他們不意外碰撞與用戶要求。 默認是true。
- CustomGrantTypeRestrictions
- 列表允許自定義授權類型被設置為當流Custom。 如果列表為空,所有自定義授權類型是允許的。 默認為空。
除了有很多設置控制刷新令牌——看到的行為在這里
Ø 例如:為隱式流配置客戶端
var client = new Client{
ClientName = "JS Client",
Enabled = true,
ClientId = "implicitclient",
Flow = Flows.Implicit,
RequireConsent = true,
AllowRememberConsent = true,
RedirectUris = new List<string>
{
"https://myapp/callback.html"
},
PostLogoutRedirectUris = new List<string>
{
"http://localhost:23453/index.html"
}}
var client = new Client{
ClientName = "JS Client",
Enabled = true,
ClientId = "implicitclient",
Flow = Flows.Implicit,
RequireConsent = true,
AllowRememberConsent = true,
RedirectUris = new List<string>
{
"https://myapp/callback.html"
},
PostLogoutRedirectUris = new List<string>
{
"http://localhost:23453/index.html"
}}
Ø 例如:為資源所有者流配置客戶端
var client = new Client{
ClientName = "Legacy Client",
Enabled = true,
ClientId = "legacy",
ClientSecrets = new List<ClientSecret>
{
new ClientSecret("4C701024-0770-4794-B93D-52B5EB6487A0".Sha256())
},
Flow = Flows.ResourceOwner,
AbsoluteRefreshTokenLifetime = 86400,
SlidingRefreshTokenLifetime = 43200,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
RefreshTokenExpiration = TokenExpiration.Sliding}
v 范圍和Claims
Ø Thinktecture.IdentityServer.Core.Models.Scope類的模型OpenID連接或OAuth2范圍。
- Enabled
- 表明如果啟用了范圍,可以請求。 默認為true。
- Name
- 范圍的名稱。 這是客戶機將使用請求的值范圍。
- DisplayName
- 為同意屏幕顯示名稱。
- Description
- 屏幕描述同意。
- Required
- 指定用戶是否可以取消屏幕上同意的范圍。 默認為false。
- Emphasize
- 指定是否同意屏幕將會強調這個范圍。 使用此設置敏感或重要的范圍。 默認為false。
- Type
- 要么Identity(OpenID連接相關)或Resource(OAuth2參考資料)。 默認為Resource。
- Claims
- 列表用戶聲稱應該納入到身份(身份范圍)或訪問令牌(資源范圍)。
- IncludeAllClaimsForUser
- 如果啟用,所有的用戶將被包含在令牌。 默認為false。
- ClaimsRule
- 確定哪些賠償規則應該被包括在令牌(這是特定於實現的)
- ShowInDiscoveryDocument
- 指定是否發現文檔中顯示這個范圍。 默認為true。
還可以指定范圍聲稱進入相應的令牌-ScopeClaim類具有以下屬性:
- Name
- Claims的名稱
- Description
- 要求的描述
- AlwaysIncludeInIdToken
- 指定是否這種說法應該出現在身份令牌(即使一個訪問令牌請求)。 只適用於標識范圍。 默認為false。
的例子role身份范圍:
var roleScope = new Scope{
Name = "roles",
DisplayName = "Roles",
Description = "Your organizational roles",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>
{
new ScopeClaim(Constants.ClaimTypes.Role, alwaysInclude: true)
}};
“AlwaysIncludeInIdentityToken”屬性指定一個特定的應該是身份標識的一部分,即使用戶信息的訪問令牌端點的請求。
例子的范圍IdentityManager API:
var idMgrScope = new Scope{
Name = "idmgr",
DisplayName = "Thinktecture IdentityManager",
Type = ScopeType.Resource,
Emphasize = true,
Claims = new List<ScopeClaim>
{
new ScopeClaim(Constants.ClaimTypes.Name),
new ScopeClaim(Constants.ClaimTypes.Role)
}};
v 身份驗證選項
這個話題可以找到的樣本在這里
的AuthenticationOptions是一個屬性的嗎IdentityServerOptions自定義登錄和注銷的觀點和行為。
- EnableLocalLogin
- 表明如果IdentityServer將允許用戶與本地帳戶進行身份驗證。 禁用此設置不會顯示用戶名/密碼表單登錄頁面。 這也將禁用資源所有者密碼流。 默認為true。
- EnableLoginHint
- 指示是否login_hint參數是用於預填充用戶名字段。 默認為true。
- LoginPageLinks
- 的列表LoginPageLink對象。 這些允許login視圖提供用戶自定義到其他web頁面的鏈接,他們可能需要訪問之前登錄(如注冊頁面,或密碼重置頁面)。
- LoginPageLink包含:
- Text:出現在鏈接的文本。
- Href:的URLhref的鏈接。
- 自定義web頁面所代表的LoginPageLink將提供的托管應用程序。 一旦執行它的任務就可以恢復登錄工作流將用戶重定向回登錄視圖。
- 當用戶遵循的一個LoginPageLink年代,signin查詢字符串參數是傳遞到頁面。 這個參數應該作為一個回響signin查詢字符串參數到登錄頁面,當用戶想恢復其登錄。 login視圖位於路徑”~ / login”相對於IdentityServer的應用基礎。
- RememberLastUsername
- 表明IdentityServer是否還記得過去的用戶名進入登錄頁面。 默認為false。
- IdentityProviders
- 允許配置額外的身份提供者——看到在這里。
- CookieOptions
- CookieOptions對象配置如何由IdentityServer餅干。
- CookieOptions這些屬性:
- Prefix:允許在餅干上設置一個前綴,以避免潛在的沖突與其他餅干使用相同的名稱。 默認情況下不使用前綴。
- ExpireTimeSpan:驗證cookie的過期時間。 默認為10個小時。
- IsPersistent:表明身份驗證cookie是否被標記為持久性。 默認為false。
- SlidingExpiration:表示如果身份驗證cookie是滑動,這意味着它自動更新用戶是活躍的。 默認為false。
- Path:設置cookie的道路。 默認為IdentityServer在托管應用程序的基本路徑。
- AllowRememberMe:表示“記住我”選項是否呈現給用戶的登錄頁面。 如果選擇這個選項將發行持續驗證cookie。 默認為true。
- 如果這個設置是使用用戶的決定(是或否)將覆蓋IsPersistent設置。 換句話說,如果兩個IsPersistent和AllowRememberMe啟用用戶決定他們不記得登錄,然后不會發行持久化cookie。
- RememberMeDuration:持久化cookie簽發時間登錄頁面上的“記住我”選項。 默認為30天。
- SecureMode:獲取或設置模式發布安全標志的餅干。 默認為SameAsRequest。
- EnableSignOutPrompt
- 表明經過IdentityServer是否會顯示一個確認頁。 當一個客戶端發起一個捲,默認情況下IdentityServer將要求用戶確認。 這是一個緩解技術對垃圾郵件“注銷”。 默認為true。
- EnablePostSignOutAutoRedirect
- 獲取或設置一個值,指出是否IdentityServer自動重定向回驗證post_logout_redirect_uri傳遞到signout端點。 默認為false。
- PostSignOutAutoRedirectDelay
- 獲取或設置重定向到一個之前延遲(以秒為單位)post_logout_redirect_uri。 默認為0。
- SignInMessageThreshold
- 獲取或設置限制之后,老signin消息(餅干)清除。 默認為5。
- InvalidSignInRedirectUrl
- 獲取或設置無效登錄重定向URL。 如果用戶到達登錄頁面沒有一個有效的登錄請求,然后他們將被重定向到該URL。 URL必須絕對或相對URL(從“~ /”)。
v 身份提供者
IdentityServer支持使用外部身份驗證提供者。 外部身份驗證機制必須封裝在一個武士刀認證中間件。
武士刀本身附帶的中間件為谷歌、Facebook、Twitter、微軟賬戶,ws - federation和OpenID連接,但也有社區開發中間件)(包括雅虎、LinkedIn和SAML2p)。 看到這里的選項列表。
為外部提供者配置中間件,添加一個方法接受一個項目IAppBuilder和一個string
public static void ConfigureIdentityProviders(IAppBuilder app, string signInAsType){
var google = new GoogleOAuth2AuthenticationOptions
{
AuthenticationType = "Google",
Caption = "Google",
SignInAsAuthenticationType = signInAsType,
ClientId = "...",
ClientSecret = "..."
};
app.UseGoogleAuthentication(google);
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
Caption = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = "...",
AppSecret = "..."
};
app.UseFacebookAuthentication(fb);
var twitter = new TwitterAuthenticationOptions
{
AuthenticationType = "Twitter",
Caption = "Twitter",
SignInAsAuthenticationType = signInAsType,
ConsumerKey = "...",
ConsumerSecret = "..."
};
app.UseTwitterAuthentication(twitter);}
筆記
AuthenticationType必須是一個獨特的價值來確定外部身份提供商。 這個值也將用於idp在生成的令牌。 而且相同的值可以用着身份提供者在使用授權/身份驗證請求acr_values參數(見這的更多信息)。 這個值也用來限制允許在身份提供者Client配置。
Caption登錄頁面上指定的標簽按鈕身份提供商。 如果Caption是一個空字符串,身份提供者在登錄頁面將不會顯示。 但仍然可以通過登錄提示。
SignInAsAuthenticationType必須設置為我們傳遞的價值通過嗎signInAsType參數
指定配置方法IdentityProviders財產的AuthenticationOptions:
var idsrvOptions = new IdentityServerOptions{
SiteName = "IdentityServer3",
Factory = factory,
SigningCertificate = Cert.Load(),
AuthenticationOptions = new AuthenticationOptions
{
IdentityProviders = ConfigureIdentityProviders
}};
app.UseIdentityServer(idsrvOptions);
v 添加ws - federation身份提供者
基於ws - federation身份提供者可以以相同的方式添加如上所示。
向后兼容性原因,ws - federation中間件聽所有傳入請求和檢查傳入令牌的帖子。 這不是一個問題,如果你只有一個ws - federation中間件配置,但是如果你有不止一個,你需要設置一個顯式的和獨特的CallbackPath屬性相匹配的回復URL配置在國內流離失所者。 請注意,CallbackPath必須相對於根目錄,而不是相對於身份服務器模塊路徑。 例如,如果外部提供者配置為post身份驗證令牌http://mydomain.com/SubFolder/IdSrv/MyExternalProvider然后CallbackPath應該設置為/SubFolder/IdSrv/MyExternalProvider。
var adfs = new WsFederationAuthenticationOptions{
AuthenticationType = "adfs",
Caption = "ADFS",
SignInAsAuthenticationType = signInAsType, MetadataAddress = "https://adfs.leastprivilege.vm/federationmetadata/2007-06/federationmetadata.xml",
Wtrealm = "urn:idsrv3"};app.UseWsFederationAuthentication(adfs);
v HSTS
HTTP嚴格的運輸安全(hst)是網絡安全的一個重要方面。 IdentityServer3提供了一個配置選項包括hst頭在它所有的HTTP響應。 要啟用,使用UseHsts擴展方法IAppBuilder在你OWIN配置:
public void Configuration(IAppBuilder app){
app.UseHsts();
// ...}
如果你想設置過期(max-age),然后UseHsts過載,接受嗎int的天數, 或者一個TimeSpan為一個自定義的持續時間。 的值0或TimeSpan.Zero可以用來清洗hst瀏覽器緩存。 默認過期30天。
v CORS
許多端點IdentityServer將通過Ajax調用從JavaScript訪問。 鑒於IdentityServer很可能比這些客戶托管在一個不同的起源,這意味着跨源資源共享(歌珥)將是一個問題。
v 歌珥政策服務
IdentityServer3允許托管應用程序來實現ICorsPolicyService確定歌珥政策。 該服務注冊的IdentityServerServiceFactory。
單一方法ICorsPolicyService是:
- Task<bool> IsOriginAllowedAsync(string origin)
- 返回true如果origin是允許的,false否則。
你可以實現一個自定義的實現在任何你認為合適的方式來確定如果調用起源是被允許的。
Ø 提供實現
有兩種實現提供從IdentityServer核心:
- DefaultCorsPolicyService
- 這個實現可以使用如果允許起源的列表允許是固定的和已知的在應用程序開始。 的AllowedOrigins屬性的集合,可以confgured的起源,應該允許列表。
- 還有一個AllowAll屬性可以設置true允許所有的起源。
- InMemoryCorsPolicyService
- 這個實現接受作為構造函數參數列表Client對象。 歌珥的起源可以通過配置AllowedCorsOrigins財產的Client對象。
有一個最后的實現提供了從IdentityServer3.EntityFramework:
- ClientConfigurationCorsPolicyService
- 這個實現了其列表允許的起源AllowedCorsOrigins財產的Client對象存儲在數據庫中。
v 棄用:CorsPolicy
在版本1.0.0 IdentityServer的CorsPolicy是唯一的方法來支持歌珥和現在已經棄用上述歌珥政策服務。 下面的文檔維護,因為1.0.0特性仍然支持,但在未來的版本將被刪除。
Ø CorsPolicy
IdentityServer3允許托管應用程序配置CorsPolicy在IdentityServerOptions控制允許哪些起源。
AllowedOrigins
的CorsPolicy有兩種方法可以指定允許哪些起源。 第一個是AllowedOrigins主機名稱的集合。 這是有用的,如果在應用程序啟動時間的起源是已知的(硬編碼或可能從數據庫加載)。
var idsvrOptions = new IdentityServerOptions();
idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myclient.com");
idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myotherclient.org);
PolicyCallback
第二個方法CorsPolicy允許托管應用程序顯示允許哪些起源是PolicyCallback代表這是一個Func<string, Task<bool>>。 在運行時調用該委托歌珥請求時被請求IdentityServer並通過原點。 一個返回bool的價值true表明,原點是被允許的。 這是有用的,如果經常更改允許起源列表或者足夠大,這樣一個數據庫查找者優先。
var idsvrOptions = new IdentityServerOptions();
idsrvOptions.CorsPolicy.PolicyCallback = async origin =>{
return await SomeDatabaseCallToCheckIfOriginIsAllowed(origin);};
CorsPolicy.AllowAll
為了方便有一個靜態屬性CorsPolicy.AllowAll這將允許所有的起源。 這是有用的調試或發展。
var idsvrOptions = new IdentityServerOptions {
CorsPolicy = CorsPolicy.AllowAll};
v 日志記錄
IdentityServer產生廣泛的日志輸出。 日志記錄機制,水槽是由通過設定一個托管應用程序LogProvider(例如,在你的startup類):
LogProvider。SetCurrentLogProvider(新 DiagnosticsTraceLogProvider());
以下供應商的支持:
l System.Diagnostics。 跟蹤(DiagnosticsTraceLogProvider)
l TraceSource(TraceSourceLogProvider)
l NLog(NLogLogProvider)
l 企業圖書館(EntLibLogProvider)
l SeriLog(SerilogLogProvider)
l Log4Net(Log4NetLogProvider)
l 放大鏡(LoupeLogProvider)
您可以創建額外的提供者的推導LogProvider。
v 配置診斷
的LoggingOptions類具有以下設置:
- EnableWebApiDiagnostics
- 如果啟用,Web API內部診斷日志記錄將被轉發到日志提供者
- WebApiDiagnosticsIsVerbose
- 如果啟用,Web API診斷日志記錄將被設置為詳細
- EnableHttpLogging
- 如果啟用,HTTP請求和響應將被記錄
- IncludeSensitiveDataInLogs
- 如果啟用,標准的日志可能包含敏感數據,如PII數據
警告 EnableHttpLogging可能的沖突與其他框架加載到相同的web應用程序(它肯定與MVC)。 您不能使用HTTP記錄在這種情況下。
v 配置系統 診斷提供者
以下代碼片段添加到您的配置文件將所有日志消息到一個簡單的文本文件。 我們使用Baretail查看日志文件。
注意:如果你使用這種方法你需要確保賬戶運行應用程序池包含日志文件的目錄有寫訪問權限。 如果你不指定一個路徑,這將是應用程序目錄,不建議生產場景。 生產記錄到一個文件外應用程序目錄。
<system.diagnostics>
<trace autoflush="true"
indentsize="4">
<listeners>
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="Trace.log" />
<remove name="Default" />
</listeners>
</trace></system.diagnostics>
v 配置TraceSource提供者
以下代碼片段添加到您的配置文件。 您可以使用服務跟蹤查看器的工具。 凈SDK檢查跟蹤文件。
<sources>
<source name="Thinktecture.IdentityServer"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "trace.svclog" />
</listeners>
</source></sources>
v 插裝自己的代碼
您還可以使用日志系統在您自己的代碼的可擴展性。
添加一個靜態ILog實例類
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
使用日志記錄器記錄你的消息
Logger.Debug("Getting claims for identity token");
v 事件
IdentityServer在運行時引發了一系列的事件,如:
l 成功/失敗身份驗證(資源所有者流,pre、片面、本地和外部)
l 令牌發出(身份、訪問刷新令牌)
l 令牌處理相關事件(授權代碼刷新令牌發出/贖回/刷新)
l 許可撤銷
l 端點成功/失敗
l 過期無效/沒有簽名證書
l 未處理的異常和內部錯誤
l CSP錯誤報告的瀏覽器。 看到CSP為更多的信息。
默認情況下這些事件轉發到日志提供者——配置 一個定制的事件服務可以處理或以任何方式提出適合環境。
v 配置事件
的EventsOptions類具有以下設置(默認false):
- RaiseSuccessEvents
- 如刷新刷新令牌或身份驗證成功
- RaiseFailureEvents
- 如身份驗證失敗,授權代碼救贖失敗
- RaiseErrorEvents
- 如未處理的異常
- RaiseInformationEvents
- 如令牌有效發行或證書
第六章端點
v 授權/身份驗證端點
授權端點可以用來請求訪問令牌或授權碼(隱式和授權代碼流)。 你可以使用一個web瀏覽器或web視圖開始這個過程。
Ø 支持參數
看到規范。
- client_id(必需)
- 客戶機的標識符
- scope(必需)
- 一個或多個注冊范圍
- redirect_uri(必需)
- 必須精確匹配的一個允許重定向uri的客戶嗎
- response_type(必需)
- code請求一個授權代碼
- token請求一個訪問令牌(只允許資源范圍)
- id_token token請求一個身份令牌和一個訪問令牌(包括資源和身份允許范圍)
- response_mode(可選)
- form_post發送令牌響應作為后一種形式,而不是一個片段編碼的重定向
- state(推薦)
- idsrv將回聲狀態值標記的回應,這是對於關聯請求和響應
- nonce(所需的身份令牌使用隱式流)
- idsrv將回聲的nonce價值身份令牌,這是關聯的令牌請求)
- prompt(可選)
- none沒有用戶界面將顯示在請求。 如果這是不可能的(例如,因為用戶必須登錄或同意)將返回一個錯誤
- login登錄界面將顯示,即使用戶擁有一個有效的會話
- login_hint(可選)
- 可用於預填寫登錄頁面上的用戶名字段
- max_age(可選)
- 如果用戶的登錄會話超過最大年齡(以秒為單位),登錄界面將顯示
- acr_values(可選)
- 允許通過額外的身份驗證相關信息用戶服務——還有價值觀具有特殊的意義:
- idp:name_of_idp繞過登錄屏幕/家庭領域,並將用戶直接轉發給所選身份提供商每客戶端配置(如果允許)
- tenant:name_of_tenant可以用來傳遞一個租戶名稱的用戶服務
- 允許通過額外的身份驗證相關信息用戶服務——還有價值觀具有特殊的意義:
Ø 例子
可讀性(URL編碼刪除)
GET /connect/authorize?client_id=client1&scope=openid email api1&response_type=id_token token&redirect_uri=https://myapp/callback&state=abc&nonce=xyz
v 令牌端點
令牌端點可以用於以編程方式請求或刷新令牌(資源所有者憑證流密碼,授權代碼流,客戶端憑證流和自定義授權類型)。
Ø 支持參數
看到規范。
- grant_type(必需)
- authorization_code, client_credentials, password, refresh_token或自定義
- scope(所需的所有授權類型除了refresh_token和代碼)
- redirect_uri(所需代碼授予類型)
- code(所需代碼授予)
- username格蘭特(所需的密碼類型)
- password(密碼grant_type所需)
- acr_values(允許密碼授權類型將額外的信息傳遞給用戶的服務)
- 有值和特殊的意義:
- idp:name_of_idp繞過登錄屏幕/家庭領域,並將用戶直接轉發給所選身份提供商每客戶端配置(如果允許)
- tenant:name_of_tenant可以使用額外的信息傳遞給用戶服務
- 有值和特殊的意義:
- refresh_token(需要刷新令牌授權)
- client_id(后的身體,或作為一個基本身份驗證頭)
- client_secret(后的身體,或作為一個基本身份驗證頭)
Ø 身份驗證
所有請求令牌端點必須經過身份驗證——要么通過基本身份驗證通過客戶機id和秘密 或添加client_id和client_secret字段的身體。
當提供client_id和client_secret在Authorization頭預計:
l client_id:client_secret
l Base64編碼的
var clientId = "...";
var clientSecret = "...";
var encoding = Encoding.UTF8;
var credentials = string.Format("{0}:{1}", clientId, clientSecret);
var headerValue = Convert.ToBase64String(encoding.GetBytes(credentials));
Ø 例子
(Form-encoding刪除和添加換行符是為了增加可讀性)
POST /connect/token
Authorization: Basic abcxyz
grant_type=authorization_code&
code=hdh922&
redirect_uri=https://myapp.com/callback
v 用戶信息端點
UserInfo端點可以用來獲取身份信息主題。 它需要一個有效的訪問令牌至少openid的范圍。
看到規范
Ø 例子
GET /connect/userinfo
Authorization: Bearer <access_token>
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "248289761001",
"name": "Bob Smith",
"given_name": "Bob",
"family_name": "Smith",
"role": [
"user",
"admin"
]
}
v 發現端點
發現端點可以用來檢索關於IdentityServer——它返回元數據信息,如發行人名稱、關鍵材料,支持范圍等。
看到規范
Ø 例子
GET /.well-known/openid-configuration
v 注銷端點
重定向到注銷端點掃清了身份驗證會話和餅干。
您可以通過以下的端點可選參數:
- id_token_hint
- 客戶機的id_token期間獲得認證。 這允許繞過注銷確認屏幕以及提供一篇注銷重定向URL
- post_logout_redirect_uri
- 一個URI,IdentityServer可以重定向到后注銷(默認情況下顯示一個鏈接)。 URI必須允許注銷后URI列表中的客戶端。
/connect/endsession?id_token_hint=...&post_logout_redirect_uri=https://myapp.com
v 令牌撤銷
這個端點允許撤銷訪問令牌(僅參考標記)和刷新令牌。 它實現了令牌撤銷規范(RFC 7009)。
支持參數:
- token(必需)
- 令牌撤銷
- token_type_hint
- 要么access_token或refresh_token
使用一個支持的請求必須經過身份驗證的客戶端身份驗證方法。
例子:
POST /connect/revocation HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token
v 訪問令牌驗證端點
訪問令牌驗證端點可以用來驗證參考標記。 它也可以用來驗證獨立JWT如果消費者沒有支持適當的JWT或加密庫。
Ø 例子
GET /connect/accesstokenvalidation?token=<token>
一個成功的響應將返回一個狀態碼200和相關申請令牌。 一次不成功的響應將返回一個400錯誤消息。
還可以通過一個范圍,預計將在令牌:
GET /connect/accesstokenvalidation?token=<token>&expectedScope=calendar
v 身份令牌驗證端點
身份令牌驗證端點可以用來驗證身份令牌。 這是有用的為客戶,無法獲得適當的JWT或加密庫(例如JavaScript)。
Ø 例子
GET /connect/identitytokenvalidation?token=<token>&client_id=<expected_client_id>
一個成功的響應將返回一個狀態碼200和相關申請令牌。 一次不成功的響應將返回一個400錯誤消息。
{
"nonce": "nonce",
"iat": "1413203421",
"sub": "88421113",
"amr": "password",
"auth_time": "1413203419",
"idp": "idsrv",
"iss": "https://idsrv3.com",
"aud": "implicitclient",
"exp": "1413203781",
"nbf": "1413203421"
}
v CSP端點
CSP允許端點配置報告。 IdentityServer CSP的錯誤記錄瀏覽器提供一個端點報告。 這些CSP錯誤將提高事件在事件系統。
CSP報告特性可以通過設置禁用EnableCspReportEndpoint財產false在EndpointOptions的一個屬性是什么IdentityServerOptions。
第七章先進的
v 刷新令牌
l 刷新令牌支持以下流:授權代碼,混合動力和資源所有者憑證流密碼。
l 客戶需要允許請求offline_access范圍刷新令牌。
Ø 設置在客戶端類
- RefreshTokenUsage
- 重用:刷新令牌處理刷新令牌時將保持不變
- 前:刷新令牌處理刷新令牌時將被更新
- RefreshTokenExpiration
- 絕對:刷新令牌將到期在一個固定的時間點(AbsoluteRefreshTokenLifetime指定的)
- 滑動:刷新令牌時,將再次刷新令牌的生命周期(通過SlidingRefreshTokenLifetime中指定的數量)。 絕對不會超過生命一生。
- AbsoluteRefreshTokenLifetime
- 一生最大的刷新令牌在幾秒鍾內。 默認為2592000秒/ 30天
- SlidingRefreshTokenLifetime
- 滑動的一生秒刷新令牌。 默認為1296000秒/ 15天
Ø 使用
l 請求offline_access范圍(通過代碼或資源所有者流)
l 使用刷新令牌refresh_token格蘭特
Ø 樣品
v 定制服務
IdentityServer3提供了許多擴展點用於存儲數據,驗證邏輯和通用功能 支持IdentityServer所需的操作作為一個令牌服務。 這些不同的擴展點統稱為“服務”。
看到在這里服務的完整列表。
v 強制性的服務
三是強制性的,必須配置的服務實現者,他們是:
l 用戶服務(IUserService)
l 客戶端存儲(IClientStore)
l 存儲(范圍IScopeStore)
我們提供一個簡單的內存版本的這三個服務以及支持通過回購或社區項目相關的數據存儲。 看到在這里為更多的細節。
v 注冊定制服務
你可以取代所有服務和注冊額外定義的。 這是封裝的Registration類。 一個Registration代表一種IdentityServer獲得您的服務的一個實例。
根據您的服務的設計您可能想要對每個請求一個新實例,使用單例, 或者你可能需要特殊的實例化邏輯每次實例是必要的。 為了適應這些不同的可能性,Registration類提供了許多不同的構造函數來注冊服務:
- new Registration<T>(Type yourImplementation)
- 寄存器yourImplementation當類實現T接口。
- new Registration<T, Impl>()
- 寄存器Impl當類實現T接口。 這個API是一個簡單方便的接受的前面Type參數。
- new Registration<T>(T singleton)
- 注冊singleton作為一個單例實現傳遞的實例T接口。
- new Registration<T>(Func<IDependencyResolver, T> factory)
- 注冊一個回調函數,將調用返回的實現T接口。
var factory = new IdentityServerServiceFactory();factory.UserService = new Registration<IUserService, MyCustomUserService>();
看到這個頁面依賴注入(DI)頁面了解更多細節。
Ø 服務清理
在所有情況下,除了單,如果您的服務實現IDisposable,然后Dispose
第八章依賴注入
這個話題可以找到的樣本在這里
IdentityServer3已經為各種服務擴展點。 默認的實現這些服務被設計為與其他IdentityServer移動部件 ,因此我們使用依賴注入一切連接起來。
v 注入IdentityServer服務
默認提供的服務可以取代IdentityServer托管應用程序(如果需要的話)。 自定義實現也可以使用依賴項注入和IdentityServer類型甚至定制類型注射。 這僅僅是支持自定義服務和商店注冊使用Registration。
定制服務接受IdentityServer定義的類型,只是表明這些依賴項作為構造函數參數。 當IdentityServer實例化你的注冊類型構造函數的參數將被自動解決。 例如:
public class MyCustomTokenSigningService: ITokenSigningService{
private readonly IdentityServerOptions _options;
public MyCustomTokenSigningService(IdentityServerOptions options)
{
_options = options;
}
public Task<string> SignTokenAsync(Token token)
{
// ...
}}
public class MyCustomTokenSigningService: ITokenSigningService{
private readonly IdentityServerOptions _options;
public MyCustomTokenSigningService(IdentityServerOptions options)
{
_options = options;
}
public Task<string> SignTokenAsync(Token token)
{
// ...
}}
這是注冊為這樣:
var factory = new IdentityServerServiceFactory();factory.TokenSigningService = new Registration<ITokenSigningService>(typeof(MyCustomTokenSigningService));
或者用這個語法:
var factory = new IdentityServerServiceFactory();factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();
v 注入定制服務
定制服務也可能依賴於你自己的類型。 這些也可以注入只要他們已經配置了IdentityServer的依賴注入系統。 這是通過添加新注冊使用IdentityServerServiceFactory的Register()方法。 例如,如果你需要定制日志記錄器服務:
public interface ICustomLogger{
void Log(string message);}
public class DebugLogger : ICustomLogger{
public void Log(string message)
{
Debug.WriteLine(message);
}}
public class MyCustomTokenSigningService: ITokenSigningService{
private readonly IdentityServerOptions _options;
private readonly ICustomLogger _logger;
public MyCustomTokenSigningService(IdentityServerOptions options, ICustomLogger logger)
{
_options = options;
_logger = logger;
}
public Task<string> SignTokenAsync(Token token)
{
// ...
}}
然后它將被登記為這樣:
var factory = new IdentityServerServiceFactory();factory.TokenSigningService = new Registration<ITokenSigningService, MyCustomTokenSigningService>();factory.Register(new Registration<ICustomLogger, MyCustomDebugLogger>());
Ø 沒有一個接口定制服務
在上面的例子中注入類型是ICustomLogger和impelemntation是MyCustomDebugLogger。 如果沒有設計定制服務接口實現單獨的合同,然后注冊的具體類型本身可以被注入。
例如,如果MyCustomTokenSigningService的構造函數不接受記錄器的接口,因此:
public class MyCustomTokenSigningService: ITokenSigningService{
public MyCustomTokenSigningService(IdentityServerOptions options, MyCustomDebugLogger logger)
{
_options = options;
_logger = logger;
}
// ...}
然后registraion可配置是這樣的:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService,
MyCustomTokenSigningService>();
factory.Register(new Registration<MyCustomDebugLogger>());
簡而言之,這種類型的注冊意味着MyCustomDebugLogger具體類型是被注入依賴的類型。
v 創建自定義
如果你的服務是必要的人工構造(如您需要傳遞特定參數的構造函數),然后您可以使用Registration類,允許一個工廠要使用回調。 這Registration這個簽名:
new Registration<T>(Func<IDependencyResolver, T> factory)
返回值必須的一個實例T接口和一個例子可能是這個樣子:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>
new MyCustomTokenSigningService("SomeSigningKeyValue"));
Ø 獲得其他依賴項
雖然這種方法允許您最靈活地創建你的服務,你還可能需要使用其他服務。 這就是IDependencyResolver用於。 它允許您從在你的回調函數得到服務。 例如,如果您的自定義客戶端存儲需要依賴於另一個服務在IdentityServer,它可以是這樣獲得的:
var factory = new IdentityServerServiceFactory();
factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>
new MyCustomTokenSigningService("SomeSigningKeyValue",
resolver.Resolve<ICustomLogger>()));
Ø 叫依賴
最后,當通過注冊自定義依賴關系IdentityServerServiceFactory的Register()方法,可以命名的依賴關系。 這個名字是表示通過name構造函數的參數Registration類。 這僅僅是用於自定義注冊和名稱只能解決依賴關系時使用IDependencyResolver在自定義工廠回調。
命名的依賴可能是有用的注冊相同的多個實例T提供一種機制來實現所需的。 例如:
string mode = "debug"; // or "release", for example
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<ICustomLogger,MyFileSystemLogger>("debug"));
factory.Register(new Registration<ICustomLogger, MyDatabaseLogger>("release"));
factory.TokenSigningService = new Registration<ITokenSigningService>(resolver =>
new MyCustomTokenSigningService(resolver.Resolve<ICustomLogger>(mode)));
在這個例子中,mode作為配置國旗impelmentation的影響ICustomLogger在運行時將使用。
v 實例化與登記模式
的Registration類允許服務顯示多少的實例將創建的服務。 的Mode屬性是一個枚舉這些可能的值:
- InstancePerHttpRequest
- 每個HTTP請求將創建一個實例。 這意味着,如果在單個服務請求兩次依賴鏈則將共享相同的實例。
- InstancePerUse
- 將創建一個實例/位置服務是必要的。 這意味着,如果在單個服務請求兩次依賴鏈然后將創建兩個單獨的實例。
- Singleton
- 只有一個實例將被創建。 當使用這種模式是自動分配Registration接受一個單例實例作為構造函數參數。
v 客戶端緩存結果、范圍和用戶存儲
有各種各樣的商店允許IdentityServer從數據庫加載數據。 鑒於IdentityServer的一般解耦設計,可以多次調用api加載數據IdentityServer相同的HTTP請求。 這可能招致不必要的往返數據庫。 考慮到這種可能性,IdentityServer定義了一個緩存接口,這樣您就可以實現自己的緩存邏輯。 此外,IdentityServer提供了一個默認的緩存實現。
v 默認的緩存
IdentityServer提供的默認緩存是一個內存中的緩存和是可配置的緩存數據的時間到期。 這個默認緩存(雖然很簡單)應該解決性能問題。 配置這個默認緩存,上有擴展方法IdentityServerServiceFactory:
l ConfigureClientStoreCache
l ConfigureScopeStoreCache
l ConfigureUserServiceCache
這些是重載要么不接受參數(使用默認的期滿5分鍾),或一個TimeSpan表明一個定制的到期值。 這些api使用這樣的:
var factory = InMemoryFactory.Create(
users: Users.Get(),
clients: Clients.Get(),
scopes: Scopes.Get());
factory.ConfigureClientStoreCache();
factory.ConfigureScopeStoreCache();
factory.ConfigureUserServiceCache(TimeSpan.FromMinutes(1));
這些方法應該被稱為后分配到合適的商店IdentityServerServiceFactory,因為他們使用裝飾模式包裝實際的存儲實現。
v 自定義緩存
如果需要自定義緩存實現(例如使用復述,),那么您可以實現的ICache<T>需要緩存的數據。 緩存接口定義了這個API:
- Task SetAsync(string key, T item)
- 的key和item緩存。
- Task<T> GetAsync(string key)
- 的key表明項目從緩存中訪問。 一個null返回條目顯示在緩存中沒有條目。
的IdentityServerServiceFactory上面描述的擴展方法也超載也接受Registration自定義緩存:
l ConfigureClientStoreCache(Registration<ICache<Client>> cacheRegistration)
l ConfigureScopeStoreCache(Registration<ICache<IEnumerable<Scope>>> cacheRegistration)
l ConfigureUserServiceCache(Registration<ICache<IEnumerable<Claim>>> cacheRegistration)
v 自定義視圖
IdentityServer3向用戶顯示不同的“觀點”。 IdentityServer視圖需要登錄,注銷提示,退出系統,同意,客戶端權限和錯誤。 這些觀點僅僅是web頁面顯示在瀏覽器中。 獲得這些視圖的標記,IdentityServer定義了IViewService接口。 視圖服務是IdentityServer的一個可選的擴展點。
Ø 默認視圖服務
可以找到這個話題的樣本在這里
視圖的默認實現IdentityServer是所使用的服務DefaultViewService。 各種資產(HTML、JavaScript、CSS和字體)組成的觀點從嵌入式資源在IdentityServer組裝。
的DefaultViewService允許一定數量的定制。
CSS和腳本定制
定制的一個簡單的方法是托管的應用程序可以提供一個列表的CSS和JavaScript文件包含在默認的web頁面。 這允許品牌而不需要完全取代資產本身。
的DefaultViewServiceOptions類是用來表示這些CSS或JavaScript文件通過Stylesheets和Scripts列表:
var viewOptions = new DefaultViewServiceOptions();
viewOptions.Stylesheets.Add("/Content/Site.css");
的路徑傳遞給Add可以是相對於IdentityServer的基本路徑前綴路徑的“~”(如“~ /道路/ file.css”),或者可以通過加前綴host-relative路徑的路徑用“/”(如“/道路/ file.css”)。 絕對url添加支持,只要他們IdentityServerCSP的選項。
然后使用DefaultViewServiceOptions有一個ConfigureDefaultViewService擴展方法IdentityServerServiceFactory。 這個助手方法使用依賴注入系統注冊DefaultViewService及其依賴項的基礎上選擇:
var viewOptions = new DefaultViewServiceOptions();
viewOptions.Stylesheets.Add("/Content/Site.css");
var factory = new IdentityServerServiceFactory();
factory.ConfigureDefaultViewService(viewOptions);
HTML定制
替換整個視圖
的DefaultViewService允許HTML的定制。 默認視圖可以通過創建HTML文件在一個“覆蓋”assets托管應用程序庫中的文件夾目錄。 文件包含在所在地的名字匹配正在呈現的視圖(例如login視圖將尋找一個文件命名login.html)。 如果這些文件存在,那么他們負責呈現的HTML視圖的全部。
替換部分的觀點
呈現其默認視圖時,DefaultViewService使用模板機制(類似於MVC)布局模板。 有一個共享的“布局”視圖,還有單獨的“部分”的觀點(一個為每個頁面需要顯示)conatin里面的內容呈現的“布局”。 當一個視圖呈現這兩個合並在一起在服務器發出一個HTML文檔。
這一點本討論的是當自定義HTML,而不是取代整個HTML文檔可以取代部分視圖。 替換的部分視圖文件位於assets文件夾只需要傑出的在名字前面加上與underscope(如。_login.html)。 這將會使用默認的布局模板,但使用自定義局部視圖。 它將被合並到布局模板合並后的HTML呈現到瀏覽器。
除了能夠取代部分視圖,也可以替換默認布局模板本身。 這可以通過創建一個命名的文件_layout.html在assets文件夾中。 的DefaultViewService將使用任何組合的自定義布局或部分觀點發現與默認的嵌入式文件系統合並資產呈現請求的視圖。
緩存
自定義視圖將默認緩存的內存,所以如果文件被改變了,那么它將需要一個應用程序重新啟動加載任何更新的HTML。 這種行為可以通過設置被禁用CacheViews財產false在DefaultViewServiceOptions前面所述。
自定義視圖加載程序
最后,如果assets文件系統上的文件夾不可取,那么您可以實現您自己的自定義存儲視圖通過implmenetingIViewLoader接口。 這是作為一個配置Registration<IViewLoader>在DefaultViewServiceOptions。
Ø 自定義視圖服務
可以找到這個話題的樣本在這里
如果托管應用程序需要完全控制視圖(HTML、CSS、JavaScript等)就可以實現的IViewService控制的所有標記呈現視圖。 自定義視圖服務將被注冊ViewService財產的IdentityServerServiceFactory。
的方法IViewService每個預計將產生一個接口Stream包含UTF8編碼標記顯示的各種視圖(登錄、同意等)。 這些方法都接受作為參數模型特定的視圖(如呈現LoginViewModel,或者一個ConsentViewModel)。 這個模型提供了上下文信息,很可能需要向用戶提供(例如客戶端和范圍在同意的觀點,或錯誤消息錯誤觀點,或URL提交憑證登錄)。
大多數視圖將需要請求回到IdentityServer內不同的端點。 這些GET和POST請求必須包含相同的輸入,默認視圖發送到服務器。 url中包含的各種模型。
反跨站點請求偽造(Anti-XSRF)
后回服務器的視圖必須包括一個form-URL-encoded anti-xsrf令牌的請求主體。 每個包含一個相關的模型AntiForgeryTokenViewModel對象的Name和Value預計的參數。 自定義視圖必須包括這些當提交用戶的輸入數據。
v 本地化的消息
消息IdentityServer創建可以通過實施本地化(或簡單地取代)ILocalizationService接口。 它定義了一個API:
l string GetString(string category, string id)
這個API是通過了category的消息。 IdentityServer只定義了三個類:
public static class LocalizationCategories
{
public const string Messages = "Messages";
public const string Events = "Events";
public const string Scopes = "Scopes";
}
的id參數顯示類別的特定信息。 各種標識符,常量定義的使用IdentityServer3.Core.Resources名稱空間。 舉例來說,這里是一個簡短的片段的常量(咨詢完整列表的代碼):
namespace IdentityServer3.Core.Resources
{
public class MessageIds
{
public const string ClientIdRequired = "ClientIdRequired";
public const string ExternalProviderError = "ExternalProviderError";
public const string Invalid_scope = "Invalid_scope";
public const string InvalidUsernameOrPassword =
"InvalidUsernameOrPassword";
public const string MissingClientId = "MissingClientId";
// ...
}
}
默認的實現ILocalizationService
v CSP
IdentityServer合並使用內容安全政策(CSP)的所有HTML頁面顯示。
Ø CspOptions
IdentityServer3允許托管應用程序配置CspOptions在IdentityServerOptions控制CSP的行為。 以下是可配置的設置:
l Enabled:指示是否啟用或禁用CSP。 默認為true。
l ScriptSrc:允許額外的script-src值被添加到默認策略。
l StyleSrc:允許額外的style-src值被添加到默認策略。
l FontSrc:允許額外的font-src值被添加到默認策略。
l ConnectSrc:允許額外的connect-src值被添加到默認策略。
CSP允許端點配置報告。 端點描述IdentityServer CSP提供了一個報告在這里
v 用戶服務
這個話題可以找到的樣本在這里
IdentityServer3定義了IUserService接口抽象底層身份管理系統用於用戶。 它為用戶提供了語義驗證與本地賬戶和外部賬戶。 它還提供了身份和聲稱IdentityServer標記和用戶所需信息端點。 此外,用戶可以控制服務工作流在登錄時用戶體驗。
的IUserService接口定義了這些方法:
- AuthenticateLocalAsync
- 此方法要求本地身份驗證(當用戶使用用戶名和密碼的對話框)。
- AuthenticateExternalAsync
- 這個方法被調用時,用戶使用一個外部身份驗證提供者。
- PreAuthenticateAsync
- 這個方法被調用之前登錄頁面。 這允許您確定用戶應該由一些樂隊的身份驗證機制(例如客戶端證書或信任的頭)。
- GetProfileDataAsync
- 調用此方法時,關於用戶要求(如令牌創建期間或通過用戶信息端點)。
- IsActiveAsync
- 這個方法被調用時服務器需要確定用戶身份仍然被認為是有效的或活動(例如,如果用戶的帳戶已停用,因為他們登錄)。
- SignOutAsync
- 這個方法被調用,當用戶信號。
v 身份驗證
三個的apiIUserService模型驗證:AuthenticateLocalAsync,AuthenticateExternalAsync,PreAuthenticateAsync。 所有這三個api傳遞SignInMessage對象代表請求登錄上下文信息。 這些上下文屬性通常從客戶機傳遞到授權端點。
的SignInMessage包含這些屬性可能感興趣的用戶服務。
l ClientId:客戶端請求登錄標識符。
l IdP:外部身份提供商要求。
l Tenant:租戶用戶預計將來自。
l LoginHint:預期的用戶名用戶將使用登錄。
l DisplayMode:顯示模式從授權請求。
l UiLocales:UI地區從授權請求。
l AcrValues:acr值通過授權請求。
除了SignInMessage,一些身份驗證方法接受額外的參數。
AuthenticateLocalAsync如果用戶輸入憑據到本地調用IdentityServer登錄頁面。 用戶名和密碼參數,以及SignInMessage。
AuthenticateExternalAsync當外部調用身份提供商是用於驗證。 的ExternalIdentity是通過了ExternalIdentity,以及SignInMessage。
的ExternalIdentity包含:
l Provider:外部身份提供者標識符。
l ProviderId:用戶的唯一標識符提供的外部身份提供商。
l Claims:要求為用戶提供從外部身份提供者。
PreAuthenticateAsync調用之前顯示登錄頁面,允許用戶自定義服務,防止登錄頁面顯示。 這通常是由於一些外部參數,通知用戶服務,用戶應該已經登錄。 只有通過了SignInMessage。
Ø 驗證結果
所有的認證方法的返回值是一個AuthenticateResult。 返回的AuthenticateResult表明許多可能的結果之一。 使用構造函數重載,表明這些結果的選擇。 結果是:
完整的登錄
完全用戶登錄身份驗證API必須產生一個subject和一個name代表用戶。 的subject是用戶服務的用戶和惟一標識符name是一個顯示的名稱 用戶將顯示在用戶界面。
可選列表Claim也可以提供。 這些說法可以是任何額外的值,用戶可能需要在其他api服務對用戶的服務。
如果用戶正在登錄,他們使用一個外部身份提供者,那么identityProvider參數也應表示。 這將是包括的idp聲稱的身份令牌和用戶信息端點。 如果用戶正在驗證本地帳戶,然后不應使用該參數(默認的Constants.BuiltInIdentityProvider而不是使用)。
還有一個可選的authenticationMethod參數的填充amrClaims。 這可以用來表示用戶身份驗證,如兩因素身份驗證,或客戶端證書。 如果不通過,password假定為本地登錄。 對於外部登錄,然后的價值external將自動用於指示一個外部身份驗證。
這些說法的完整(subject, name, idp, amr和列表Claim)是用於填充為用戶發出的認證cookie IdentityServer。 這種身份驗證cookie發行和管理通過使用武士刀cookie驗證中間件的AuthenticationType的常數Constants.PrimaryAuthenticationType。
的ClaimsPrincipal從創建完整的登錄然后用作參數的其他apiIUserService。 這些api是GetProfileDataAsync, IsActiveAsync,SignOutAsync。
部分登錄(重定向)
除了一個完整的登錄,身份驗證api可以執行“部分登錄”。 部分登錄表明用戶已經證明他們的身份,有本地帳戶,但尚未允許繼續。 他們必須首先執行其他操作之前或提供其他數據完全被允許登錄。 這是有用的定制用戶的工作流之前讓他們完全登錄。 這可能是有用的,迫使用戶填寫注冊頁面,改變密碼,或者接受EULA之前讓他們繼續下去。
這部分執行登錄通過發行使用武士刀的“部分登錄”餅干餅干中間件的身份驗證AuthenticationType的常數Constants.PartialSignInAuthenticationType。
部分的登錄顯示所有相同的參數如上所述登錄(即為一個完整的。subject, name, claims, amr,idp)以及redirectPath。 的redirectPath代表了一個自定義web頁面提供的托管應用程序,用戶將被重定向到。 在用戶的web頁面subject和name聲稱可以用來識別用戶(除了所有其他Claims表示)。 為了獲得這些說法,頁面必須使用武士刀驗證中間件來驗證Constants.PartialSignInAuthenticationType身份驗證類型,或僅僅是執行在同一個餅干路徑IdentityServer在web服務器。
一旦用戶自定義web頁面已經完成他們的工作,他們可以被重定向回IdentityServer繼續登錄過程。 提供的URL將用戶重定向回的ClaimsConstants.PartialSignInAuthenticationType身份驗證類型並確定的要求類型Constants.ClaimTypes.PartialLoginReturnUrl。
外部登錄(重定向)
可能用戶執行外部認證,但是沒有為用戶本地帳戶。 一個定制的用戶服務可以選擇重定向用戶沒有本地帳戶。 這是通過創建一個執行AuthenticateResult與重定向ExternalIdentity傳遞到AuthenticateExternalAsyncAPI。 這個執行部分登錄(如通過以上PartialSignInAuthenticationType),但沒有在發布了餅干。 取而代之的是Claims的類型external_provider_user_id(或通過Constants.ClaimTypes.ExternalProviderUserId),其Issuer是外部提供者標識符的值是外部提供者的用戶標識符。 這些值可以用於創建一個本地帳戶並將外部賬戶相關聯。
一旦用戶完成注冊自定義web頁面,就可以重定向回IdentityServer通過相同的PartialLoginReturnUrl如上所述。
登錄錯誤
最后,驗證api可以提供一個錯誤,將會顯示在登錄視圖。 這是表示通過創建AuthenticateResult使用構造函數,它接受一個string(錯誤)作為其參數。
第九章部署
請注意本文檔是正在進行的工作。 隨時添加新的內容。
v 數據保護
如果您正在運行在IIS,您需要同步機鍵。 如果您正在運行IIS之外, 您需要使用武士刀的web農場兼容的數據保護。
不幸的是,刀不附帶一個開箱即用的。 IdentityServer包括一個數據保護的基礎上 X。 509證書(X509CertificateDataProtector),您可以設置的選項類。
v 終止SSL
如果你想終止SSL負載均衡器,有兩個相關的設置選項:
- RequireSsl
- 設置為false,允許非ssl負載均衡器和IdentityServer之間的連接。
- PublicOrigin
- 因為你的農場內部節點比公共可訪問的地址有不同的名稱,IdentityServer不能使用它 鏈接的一代。 向公眾洞穴這個屬性的名字。
v 簽名密鑰
確保簽名證書部署到所有節點。
v 配置數據
作用域的配置數據,客戶和用戶必須同步。
他們要么是靜態的,你改變通過持續部署配置數據,或者你使用持久層 實體框架回購(MongoDB或社區的貢獻)。
v 操作數據
一些功能需要操作數據的共享數據庫,即授權代碼,參考令牌和刷新令牌。 如果你使用這些功能需要一個持久層。 你可以使用我們implemenation實體框架。
v 緩存
IdentityServer有一個簡單的內置內存緩存。 這是有用的但不像它可以優化網絡農場。 你可以插入自己的緩存實現ICache
第十章實體框架支持客戶、范圍和操作數據
v 概述
支持實體框架IdentityServer來源這回購。
v 配置客戶機和范圍
如果范圍或客戶數據需要從數據庫加載(而不是使用內存配置),然后提供一個基於實體框架的實現IClientStore和IScopeStore服務。更多的信息。
v 操作數據
另外,強烈建議操作數據(如授權碼,刷新令牌,參考標記,和用戶同意)被保存在數據庫中。 因此,我們也有實體框架的實現IAuthorizationCodeStore, ITokenHandleStore, IRefreshTokenStore,IConsentStore服務。更多的信息
v 客戶和范圍
v 商店
Ø ClientStore
的ClientStore的EF-based實現嗎IClientStore接口。 它可以單獨使用的ScopeStore。
Ø ScopeStore
的ScopeStore的EF-based實現嗎IScopeStore接口。 它可以單獨使用的ClientStore。
v 登記
使用的商店,他們需要注冊。 上有擴展方法IdentityServerServiceFactory允許商店都進行配置。 所有的擴展方法接受一個EntityFrameworkServiceOptions它包含這些屬性:
l ConnectionString:配置連接字符串的名字.config文件。
l Schema:一個可選的數據庫模式使用的表。 如果沒有提供,則將使用默認數據庫。
配置獨立商店,這段代碼可以使用:
var efConfig = new EntityFrameworkServiceOptions {
ConnectionString = "SomeConnectionName",
//Schema = "someSchemaIfDesired"};
var factory = new IdentityServerServiceFactory();
factory.RegisterClientStore(efConfig);
factory.RegisterScopeStore(efConfig);
如果兩個商店將使用相同的EntityFrameworkServiceOptions,然后提供一個方便的擴展方法:
var efConfig = new EntityFrameworkServiceOptions {
ConnectionString = "SomeConnectionName",
//Schema = "someSchemaIfDesired"};
var factory = new IdentityServerServiceFactory();
factory.RegisterConfigurationServices(efConfig);
第十一章操作數據
IdentityServer3的許多特性的數據庫需要堅持各種運營數據。 這包括授權碼,刷新令牌,參考標記和用戶同意。
登記
有各種各樣的商店將持久化操作數據。 這些都是配置了一個擴展方法IdentityServerServiceFactory。 所有的擴展方法接受一個EntityFrameworkServiceOptions它包含這些屬性:
l ConnectionString:配置連接字符串的名字.config文件。
l Schema:一個可選的數據庫模式使用的表。 如果沒有提供,則將使用默認數據庫。
配置操作數據存儲可以使用這段代碼:
var efConfig = new EntityFrameworkServiceOptions {
ConnectionString = "SomeConnectionName",
//Schema = "someSchemaIfDesired"};
var factory = new IdentityServerServiceFactory();
factory.RegisterOperationalServices(efConfig);
v 數據清理
大部分的操作數據已經過期。 很可能需要移除這個陳舊的數據。 可以承載IdentityServer以外的應用程序或數據庫本身(通過各種機制)。 如果需要你執行這個清理應用程序代碼,那么TokenCleanup類提供協助。 它接受一個EntityFrameworkServiceOptions和一個Int32時間間隔(以秒為單位)來配置陳舊的數據清理的頻率。 它將異步連接到數據庫,可以配置為:
var efConfig = new EntityFrameworkServiceOptions {
ConnectionString = connString,
//Schema = "foo"};
var cleanup = new TokenCleanup(efConfig, 10);cleanup.Start();
第十二章模式變化和遷移
IdentityServer3增強,數據庫模式很可能會發生變化。 的預期模式變化,建議(和預期)托管應用程序負責處理這些模式會隨着時間而改變。
實體框架提供了遷移作為一個方法來處理模式變化和更新您的數據庫與變化。
v dbcontext
有三種不同的DbContext派生類中包含的EF的實現。 它們是:
l ClientConfigurationDbContext
l ScopeConfigurationDbContext
l OperationalDbContext
這些需要,因為數據庫上下文類(即在一個不同的裝配。Thinktecture.IdentityServer3.EntityFramework比托管應用程序)。
v 使遷移
遷移必須為每個數據庫創建上下文類。 使遷移的所有數據庫上下文類,可以使用下面的命令從包管理器控制台:
Enable-Migrations -MigrationsDirectory Migrations\ClientConfiguration -ContextTypeName ClientConfigurationDbContext -ContextAssemblyName Thinktecture.IdentityServer3.EntityFramework -ConnectionStringName IdSvr3Config
Enable-Migrations -MigrationsDirectory Migrations\ScopeConfiguration -ContextTypeName ScopeConfigurationDbContext -ContextAssemblyName Thinktecture.IdentityServer3.EntityFramework -ConnectionStringName IdSvr3Config
Enable-Migrations -MigrationsDirectory Migrations\OperationalConfiguration -ContextTypeName OperationalDbContext -ContextAssemblyName Thinktecture.IdentityServer3.EntityFramework -ConnectionStringName IdSvr3Config
最初的模式必須被定義為每個遷移(又一個),因此:
Add-Migration -Name InitialCreate -ConfigurationTypeName Host.Migrations.ScopeConfiguration.Configuration -ConnectionStringName IdSvr3Config
Add-Migration -Name InitialCreate -ConfigurationTypeName Host.Migrations.ClientConfiguration.Configuration -ConnectionStringName IdSvr3Config
Add-Migration -Name InitialCreate -ConfigurationTypeName Host.Migrations.OperationalConfiguration.Configuration -ConnectionStringName IdSvr3Config
然后可以創建數據庫:
Update-Database -ConfigurationTypeName Host.Migrations.ClientConfiguration.Configuration -ConnectionStringName IdSvr3Config
Update-Database -ConfigurationTypeName Host.Migrations.ScopeConfiguration.Configuration -ConnectionStringName IdSvr3Config
Update-Database -ConfigurationTypeName Host.Migrations.OperationalConfiguration.Configuration -ConnectionStringName IdSvr3Config
一旦你的應用程序更新到新版本,那么您可以使用Add-Migration和Update-Database更新到新模式。 檢查英孚文檔為更多的細節。
第十三章ws - federation
v 添加ws - federation支持
IdentityServer支持ws - federation充當一個身份提供商 允許外部身份驗證通過ws - federation協議。 外部認證見在這里。
這部分是關於添加ws - federation IdentityServer3身份提供者的功能。
ws - federation IdentityServer3支持是一個插件,使用的實現。 NET 4.5 System.IdentityModel。 服務組裝。 您首先需要安裝插件使用Nuget:
install-package Thinktecture.IdentityServer3.WsFederation
然后您可以連接插件實現PluginConfiguration回調的IdentityServerOptions類是這樣的:
public void Configuration(IAppBuilder appBuilder)
{
var options = new IdentityServerOptions
{
SiteName = "Thinktecture IdentityServer3 with WsFed",
SigningCertificate = Certificate.Get(),
Factory = factory,
PluginConfiguration = ConfigureWsFederation
};
appBuilder.UseIdentityServer(options);
}
private void ConfigureWsFederation(IAppBuilder pluginApp, IdentityServerOptions options)
{
var factory = new WsFederationServiceFactory(options.Factory);
// data sources for in-memory services
factory.Register(new Registration<IEnumerable<RelyingParty>>(RelyingParties.Get()));
factory.RelyingPartyService = new Registration<IRelyingPartyService>(typeof(InMemoryRelyingPartyService));
var wsFedOptions = new WsFederationPluginOptions
{
IdentityServerOptions = options,
Factory = factory
};
pluginApp.UseWsFederationPlugin(wsFedOptions);
}
相當於一個OpenID連接或在ws - federation OAuth2端叫做依賴方。 類似於其他內存工廠(見在這里)ws - federation插件對檢索的內置支持從一個內存中的服務依賴方。
看到在這里
v 定義依賴方
的RelyingParty類模型依賴方:
- Name
- 顯示名稱
- Enabled
- (默認為啟用/禁用true)
- Realm
- 依賴方的唯一標識符
- ReplyUrl
- URL發送令牌回
- TokenType
- 類型的令牌(默認為SAML2),支持以下類型:
- urn:oasis:names:tc:SAML:1.0:assertion (SAML 1.1)
- urn:oasis:names:tc:SAML:2.0:assertion (SAML 2.0)
- urn:ietf:params:oauth:token-type:jwt (JWT)
- 類型的令牌(默認為SAML2),支持以下類型:
- TokenLifeTime
- 令牌一生在幾分鍾內(默認值為480)
- EncryptingCertificate
- 證書加密令牌(SAML)
- IncludeAllClaimsForUser
- 包括所有可用的用戶令牌(而不是顯式的映射)
- DefaultClaimTypeMappingPrefix
- 默認的輸出要求類型如果前綴IncludeAllClaimsForUser但不存在顯式的映射。
- ClaimMappings
- 允許設置一個映射表從內部Claims類型外向Claims類型(情況 有地圖的沖動如name來http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name)
- SamlNameIdentifierFormat
- 允許設置SAML的SAML名稱標識符格式名稱ID
- SignatureAlgorithm
- 允許設置令牌的簽名算法(默認為RSASHA256)
- DigestAlgorithm
- 允許設置摘要算法(默認為SHA256)
v 端點
ws - federation插件包含兩個端點
v 登錄/出
這是主要的ws - federation端點的簽字。
支持參數:
- wa
- 必須是wsignin1.0簽署的或wsignout1.0對於簽署
- wtrealm
- 依賴方的領域
- wctx
- 上下文是圓絆倒依賴方(類似state在OAuth2)
- whr
- 外部身份提供商使用的名稱(跳過選擇屏幕)
示例(可讀性編碼刪除):
/wsfed?wa=wsignin1.0&wtrealm=rp1&whr=Google
v 元數據
返回元數據文檔:
/wsfed/metadata
第十四章資源
v 資源
Ø 規范
l OAuth2規范
Ø 文章
l 混合流
l 注銷后重定向
l 注銷后自動重定向
l 斯科特·布雷迪:IdentityServer3獨立實現pt。1
l 斯科特·布雷迪:IdentityServer3獨立實現pt。2
l 斯科特·布雷迪:IdentityServer3獨立實現pt。3
Ø 視頻
l 介紹OpenID連接,OAuth2 IdentityServer
Ø 培訓
l 布魯克和多明尼克的身份和訪問控制的現代Web應用程序和api車間
l 建立和確保一個RESTful api的多個客戶端ASP。 凈在PluralSight
v 社區插件
l ElasticSearch / Kibana EventService
l 復述,緩存
第十五章中間件為外部認證
v 微軟的武士刀
l OpenID連接
l 谷歌
l 推特
l 微軟賬戶
l 臉譜網
v SAML2p
l KentorIT認證服務——看到也這博客
v 其他社區的貢獻