IdentityServer3javascript
目錄css
目錄 1html
第一章 IdentityServer3 1.x 5前端
v 超連接 5html5
Ø 概述 5java
Ø 配置 5git
Ø 端點 5github
Ø 先進的 5web
Ø 實體框架支持客戶、範圍和操做數據 6redis
Ø 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
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 模式變化和遷移
l 定義依賴方
l 端點
l 概述
l 社區插件
l 中間件爲外部認證
大多數現代應用程序看起來或多或少是這樣的:
典型的交互:
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應用程序。
規範、文檔對象模型使用一個特定的術語,你應該知道的。
IdentityServer OpenID提供者鏈接,它實現了OpenID鏈接協議(以及OAuth2)。
不一樣的文獻使用不一樣的條款相同的角色,你也可能找到安全令牌服務, 身份提供者,受權服務器,IP-STS等等。
但總而言之都是同樣的:一個軟件問題給客戶的安全令牌。
IdentityServer有不少工做和功能,包括:
l 驗證用戶使用本地賬戶存儲或經過外部身份提供者
l 提供會話管理和單點登陸
l 管理和認證的客戶
l 問題客戶身份和訪問令牌
l 驗證令牌
客戶端是一個軟件,請求令牌從IdentityServer——對一個用戶進行身份驗證或 一般用於訪問資源(也稱爲依賴方或RP)。 客戶端必須註冊與OP。
客戶是web應用程序的例子,本地移動或桌面應用程序,水療,服務器進程等。
用戶是一我的類,使用一個註冊客戶機來訪問他或她的數據。
做用域標識符爲客戶想要訪問的資源。 這個標識符在一個發送給OP 身份驗證或令牌的請求。
默認狀況下容許每一個客戶機請求令牌爲每一個範圍,可是你能夠限制。
他們有兩種口味。
請求關於用戶的標識信息(又名聲稱),如他的名字或電子郵件地址被建模爲一個範圍的OpenID鏈接。
若有一個範圍profile首選,包括名字、姓、用戶名、性別、證件照以及更多。 你能夠讀到標準範圍在這裏你能夠建立本身的範圍IdentityServer模型本身的需求。
資源範圍肯定web api(也稱爲資源服務器)——你能夠如命名範圍calendar表明你的日曆API。
客戶請求令牌的相機會取決於請求的範圍,OP會返回一個身份令牌,一個訪問令牌,或二者兼而有之。
能夠經過客戶端驗證身份令牌。
它包含有關用戶的信息和細節在OP用戶身份驗證。 身份令牌表明一個成功的身份驗證。
一個訪問令牌能夠由資源進行驗證。
客戶請求訪問令牌和轉發他們的API。 訪問令牌包含客戶端和用戶信息(若是存在)。 api使用這些信息來受權訪問他們的數據。
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)
IdentityServer由nuget包的數量。
包含核心IdentityServer對象模型、服務和服務器。 只包含核心支持內存配置和用戶的商店,可是你能夠經過配置插件支持其餘商店。 這是另外一個回購和包。
存儲配置數據(客戶和範圍)以及運行時數據(贊成,令牌處理,刷新令牌)。
(社區貢獻)MongoDbgithub
支持身份管理庫。
MembershipReboot nuget | github
ASP.Net Identity nuget | github
協議插件。
OWIN中間件api。 提供了一種簡便的方法來驗證訪問令牌和實施範圍的要求。
此外,咱們發佈dev /臨時構建MyGet。 Visual Studio下面添加到你若是你想給他們一個嘗試:
https://www.myget.org/F/identity/
這個介紹的目的是建立簡單的IdentityServer安裝做爲一個OAuth2受權服務器。 這是應該讓你開始的一些基本特性和配置選項(能夠找到完整的源代碼在這裏)。 還有其餘更高級的演練的文檔以後你能夠作。 本教程包括:
l 建立一個自託管IdentityServer
l 爲應用程序設置客戶服務通訊使用應用程序賬戶和表明一個用戶
l 註冊一個API
l 請求訪問令牌
l 調用一個API
l 驗證一個訪問令牌
首先,咱們將建立一個控制檯主機和設置IdentityServer。
首先建立一個標準的控制檯應用程序並添加IdentityServer經過nuget:
install-package Thinktecture.IdentityServer3
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被實現爲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。 爲此咱們將武士刀自託管包添加到控制檯應用程序:
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...。
在這一部分,咱們將添加一個簡單的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由於必要的訪問令牌是失蹤。
在接下來的部分,咱們將添加一個簡單的控制檯客戶端請求一個訪問令牌和使用進行身份驗證的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"}在您的控制檯。
到目前爲止,客戶端請求的訪問令牌自己,沒有用戶。 讓咱們介紹一我的。
用戶服務管理用戶,對於此示例,咱們將使用簡單的內存的用戶服務。 首先咱們須要定義一些用戶:
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())
}
}
};
}}
當一我的類,將包含訪問令牌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。
這演練了一個很是簡單的OAuth2場景。 下一個你能夠試試:
l 其餘流,如隱式、代碼或混合。 他們都是推進者等高級場景聯合會和外部的身份
l 鏈接到您的用戶數據庫,經過編寫本身的用戶服務或使用咱們的開箱即用的支持ASP.Net Identity和MembershipReboot
l 客戶端和範圍配置存儲在一個數據存儲。 咱們有現成的實體框架支持。
l 使用OpenID鏈接和添加身份驗證和身份令牌標識範圍
l 本教程將引導您完成必要的步驟來獲得一個最小IdentityServer啓動並運行。 爲簡單起見,咱們將主機IdentityServer和客戶端在同一web應用程序,這可能不是一個很是現實的場景中,但可讓你開始沒有使它太複雜。
能夠找到完整的源代碼在這裏。
在第一部分,咱們將建立一個簡單的MVC應用程序並經過IdentityServer添加身份驗證。 而後咱們會仔細看看Claims,Claims轉換和受權
在Visual Studio 2013中,建立一個標準的MVC應用程序和身份驗證設置爲「無身份驗證」。
如今您能夠切換項目SSL使用屬性窗口:
重要的別忘了更新在您的項目中開始URL屬性。
IdentityServer基於OWIN /刀和分佈式Nuget包。 將其添加到新建立的web主機,安裝如下兩個方案:
install-package Microsoft.Owin.Host.Systemweb
install-package Thinktecture.IdentityServer3
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——這能夠經過提供一個簡單的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添加到您的網站。 配置,不然咱們的一些嵌入式資產由IIS將不能正確加載:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" /></system.webServer>
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"
});
啓動認證與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>
點擊連接將觸發身份驗證。 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在谷歌的開發者控制檯。 這包括幾個步驟。
首先導航到:
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與谷歌聲稱丟失時登陸。 頗有意義,由於谷歌沒有角色的概念。 作好準備,並不是全部的身份提供者將提供相同的聲明類型。
在這部分咱們將添加一個Web API的解決方案。 API將由IdentityServer擔保。 接下來咱們的MVC應用程序將調用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);
}}
一如既往地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發現文檔(元數據)。
接下來咱們須要註冊的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;
}}
接下來咱們將調用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包含兩個部分:
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使用用戶的身份。 這是經過添加完成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(「角色」)
}}
IdentityServer3打包爲中間件和使用典型的「選項」模式配置:
public void Configuration(IAppBuilder appBuilder){
var options = new IdentityServerOptions
{
SigningCertificate = Certificate.Get(),
Factory = factory,
};
appBuilder.UseIdentityServer(options);}
的IdentityServerOptionsIdentityServer類包含全部配置。 一部分由發行人的簡單屬性名稱或網站標題,您能夠從任何你認爲合適的來源(靜態代碼中,配置文件或數據庫)。 另外一部分是所謂的服務工廠充當註冊IdentityServer內部處理的某些方面。
網頁提供的文件做爲嵌入式IdentityServer議會內部的資產。 當在IIS託管或IIS Express容許這些文件送達RAMMFAR(runAllManagedModulesForAllRequests)須要在web . config中啓用:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
看到樣品
的IdentityServerOptions 類的頂層容器IdentityServer的全部配置設置。
IdentityServer3包含許多功能實現OpenID和OAuth2鏈接。 許多這些功能設計,這樣他們就能夠被取代。 這將是有用的場景缺省邏輯不匹配託管應用程序的需求,或者只是應用程序但願提供一個徹底不一樣的實現。 事實上,有些在IdentityServer3擴展點,須要提供的託管應用程序(如存儲配置數據或驗證的身份管理實現用戶的憑證)。
的Thinktecture.IdentityServer.Core.Configuration.IdentityServerServiceFactory擁有全部這些構建塊,必須提供在啓動時使用IdentityServerOptions類(見在這裏有關配置選項的更多信息)。
擴展點分爲三類。
的InMemoryFactory容許設置一個服務工廠經過爲用戶提供內存存儲,客戶和範圍(見在這裏)。
看到在這裏有關注冊定製服務的更多信息和存儲的實現。
內存廠是一個簡單的方法來獲得一個測試/ 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應用程序(連接)。
除了有不少設置控制刷新令牌——看到的行爲在這裏
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}
還能夠指定範圍聲稱進入相應的令牌-ScopeClaim類具備如下屬性:
的例子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)
}};
這個話題能夠找到的樣本在這裏
的AuthenticationOptions是一個屬性的嗎IdentityServerOptions自定義登陸和註銷的觀點和行爲。
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);
基於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);
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天。
許多端點IdentityServer將經過Ajax調用從JavaScript訪問。 鑑於IdentityServer極可能比這些客戶託管在一個不一樣的起源,這意味着跨源資源共享(歌珥)將是一個問題。
IdentityServer3容許託管應用程序來實現ICorsPolicyService肯定歌珥政策。 該服務註冊的IdentityServerServiceFactory。
單一方法ICorsPolicyService是:
你能夠實現一個自定義的實如今任何你認爲合適的方式來肯定若是調用起源是被容許的。
有兩種實現提供從IdentityServer核心:
有一個最後的實現提供了從IdentityServer3.EntityFramework:
在版本1.0.0 IdentityServer的CorsPolicy是惟一的方法來支持歌珥和如今已經棄用上述歌珥政策服務。 下面的文檔維護,由於1.0.0特性仍然支持,但在將來的版本將被刪除。
IdentityServer3容許託管應用程序配置CorsPolicy在IdentityServerOptions控制容許哪些起源。
AllowedOrigins
的CorsPolicy有兩種方法能夠指定容許哪些起源。 第一個是AllowedOrigins主機名稱的集合。 這是有用的,若是在應用程序啓動時間的起源是已知的(硬編碼或可能從數據庫加載)。
var idsvrOptions = new IdentityServerOptions();
idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myclient.com");
idsrvOptions.CorsPolicy.AllowedOrigins.Add("http://myotherclient.org);
第二個方法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};
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。
的LoggingOptions類具備如下設置:
警告 EnableHttpLogging可能的衝突與其餘框架加載到相同的web應用程序(它確定與MVC)。 您不能使用HTTP記錄在這種狀況下。
如下代碼片斷添加到您的配置文件將全部日誌消息到一個簡單的文本文件。 咱們使用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>
如下代碼片斷添加到您的配置文件。 您可使用服務跟蹤查看器的工具。 淨SDK檢查跟蹤文件。
<sources>
<source name="Thinktecture.IdentityServer"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "trace.svclog" />
</listeners>
</source></sources>
您還可使用日誌系統在您本身的代碼的可擴展性。
添加一個靜態ILog實例類
private readonly static ILog Logger = LogProvider.GetCurrentClassLogger();
使用日誌記錄器記錄你的消息
Logger.Debug("Getting claims for identity token");
IdentityServer在運行時引起了一系列的事件,如:
l 成功/失敗身份驗證(資源全部者流,pre、片面、本地和外部)
l 令牌發出(身份、訪問刷新令牌)
l 令牌處理相關事件(受權代碼刷新令牌發出/贖回/刷新)
l 許可撤銷
l 端點成功/失敗
l 過時無效/沒有簽名證書
l 未處理的異常和內部錯誤
l CSP錯誤報告的瀏覽器。 看到CSP爲更多的信息。
默認狀況下這些事件轉發到日誌提供者——配置 一個定製的事件服務能夠處理或以任何方式提出適合環境。
的EventsOptions類具備如下設置(默認false):
受權端點能夠用來請求訪問令牌或受權碼(隱式和受權代碼流)。 你可使用一個web瀏覽器或web視圖開始這個過程。
看到規範。
可讀性(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
令牌端點能夠用於以編程方式請求或刷新令牌(資源全部者憑證流密碼,受權代碼流,客戶端憑證流和自定義受權類型)。
看到規範。
全部請求令牌端點必須通過身份驗證——要麼經過基自己份驗證經過客戶機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
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"
]
}
發現端點能夠用來檢索關於IdentityServer——它返回元數據信息,如發行人名稱、關鍵材料,支持範圍等。
看到規範
GET /.well-known/openid-configuration
重定向到註銷端點掃清了身份驗證會話和餅乾。
您能夠經過如下的端點可選參數:
/connect/endsession?id_token_hint=...&post_logout_redirect_uri=https://myapp.com
這個端點容許撤銷訪問令牌(僅參考標記)和刷新令牌。 它實現了令牌撤銷規範(RFC 7009)。
支持參數:
使用一個支持的請求必須通過身份驗證的客戶端身份驗證方法。
例子:
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
訪問令牌驗證端點能夠用來驗證參考標記。 它也能夠用來驗證獨立JWT若是消費者沒有支持適當的JWT或加密庫。
GET /connect/accesstokenvalidation?token=<token>
一個成功的響應將返回一個狀態碼200和相關申請令牌。 一次不成功的響應將返回一個400錯誤消息。
還能夠經過一個範圍,預計將在令牌:
GET /connect/accesstokenvalidation?token=<token>&expectedScope=calendar
身份令牌驗證端點能夠用來驗證身份令牌。 這是有用的爲客戶,沒法得到適當的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"
}
CSP容許端點配置報告。 IdentityServer CSP的錯誤記錄瀏覽器提供一個端點報告。 這些CSP錯誤將提升事件在事件系統。
CSP報告特性能夠經過設置禁用EnableCspReportEndpoint財產false在EndpointOptions的一個屬性是什麼IdentityServerOptions。
l 刷新令牌支持如下流:受權代碼,混合動力和資源全部者憑證流密碼。
l 客戶須要容許請求offline_access範圍刷新令牌。
l 請求offline_access範圍(經過代碼或資源全部者流)
l 使用刷新令牌refresh_token格蘭特
IdentityServer3提供了許多擴展點用於存儲數據,驗證邏輯和通用功能 支持IdentityServer所需的操做做爲一個令牌服務。 這些不一樣的擴展點統稱爲「服務」。
看到在這裏服務的完整列表。
三是強制性的,必須配置的服務實現者,他們是:
l 用戶服務(IUserService)
l 客戶端存儲(IClientStore)
l 存儲(範圍IScopeStore)
咱們提供一個簡單的內存版本的這三個服務以及支持經過回購或社區項目相關的數據存儲。 看到在這裏爲更多的細節。
你能夠取代全部服務和註冊額外定義的。 這是封裝的Registration類。 一個Registration表明一種IdentityServer得到您的服務的一個實例。
根據您的服務的設計您可能想要對每一個請求一個新實例,使用單例, 或者你可能須要特殊的實例化邏輯每次實例是必要的。 爲了適應這些不一樣的可能性,Registration類提供了許多不一樣的構造函數來註冊服務:
var factory = new IdentityServerServiceFactory();factory.UserService = new Registration<IUserService, MyCustomUserService>();
看到這個頁面依賴注入(DI)頁面瞭解更多細節。
在全部狀況下,除了單,若是您的服務實現IDisposable,而後Dispose
這個話題能夠找到的樣本在這裏
IdentityServer3已經爲各類服務擴展點。 默認的實現這些服務被設計爲與其餘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>();
定製服務也可能依賴於你本身的類型。 這些也能夠注入只要他們已經配置了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具體類型是被注入依賴的類型。
若是你的服務是必要的人工構造(如您須要傳遞特定參數的構造函數),而後您可使用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在運行時將使用。
的Registration類容許服務顯示多少的實例將建立的服務。 的Mode屬性是一個枚舉這些可能的值:
有各類各樣的商店容許IdentityServer從數據庫加載數據。 鑑於IdentityServer的通常解耦設計,能夠屢次調用api加載數據IdentityServer相同的HTTP請求。 這可能招致沒必要要的往返數據庫。 考慮到這種可能性,IdentityServer定義了一個緩存接口,這樣您就能夠實現本身的緩存邏輯。 此外,IdentityServer提供了一個默認的緩存實現。
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,由於他們使用裝飾模式包裝實際的存儲實現。
若是須要自定義緩存實現(例如使用複述,),那麼您能夠實現的ICache<T>須要緩存的數據。 緩存接口定義了這個API:
的IdentityServerServiceFactory上面描述的擴展方法也超載也接受Registration自定義緩存:
l ConfigureClientStoreCache(Registration<ICache<Client>> cacheRegistration)
l ConfigureScopeStoreCache(Registration<ICache<IEnumerable<Scope>>> cacheRegistration)
l ConfigureUserServiceCache(Registration<ICache<IEnumerable<Claim>>> cacheRegistration)
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預計的參數。 自定義視圖必須包括這些當提交用戶的輸入數據。
消息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
IdentityServer合併使用內容安全政策(CSP)的全部HTML頁面顯示。
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提供了一個報告在這裏
這個話題能夠找到的樣本在這裏
IdentityServer3定義了IUserService接口抽象底層身份管理系統用於用戶。 它爲用戶提供了語義驗證與本地帳戶和外部帳戶。 它還提供了身份和聲稱IdentityServer標記和用戶所需信息端點。 此外,用戶能夠控制服務工做流在登陸時用戶體驗。
的IUserService接口定義了這些方法:
三個的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(錯誤)做爲其參數。
請注意本文檔是正在進行的工做。 隨時添加新的內容。
若是您正在運行在IIS,您須要同步機鍵。 若是您正在運行IIS以外, 您須要使用武士刀的web農場兼容的數據保護。
不幸的是,刀不附帶一個開箱即用的。 IdentityServer包括一個數據保護的基礎上 X。 509證書(X509CertificateDataProtector),您能夠設置的選項類。
若是你想終止SSL負載均衡器,有兩個相關的設置選項:
確保簽名證書部署到全部節點。
做用域的配置數據,客戶和用戶必須同步。
他們要麼是靜態的,你改變經過持續部署配置數據,或者你使用持久層 實體框架回購(MongoDB或社區的貢獻)。
一些功能須要操做數據的共享數據庫,即受權代碼,參考令牌和刷新令牌。 若是你使用這些功能須要一個持久層。 你可使用咱們implemenation實體框架。
IdentityServer有一個簡單的內置內存緩存。 這是有用的但不像它能夠優化網絡農場。 你能夠插入本身的緩存實現ICache
支持實體框架IdentityServer來源這回購。
若是範圍或客戶數據須要從數據庫加載(而不是使用內存配置),而後提供一個基於實體框架的實現IClientStore和IScopeStore服務。更多的信息。
另外,強烈建議操做數據(如受權碼,刷新令牌,參考標記,和用戶贊成)被保存在數據庫中。 所以,咱們也有實體框架的實現IAuthorizationCodeStore, ITokenHandleStore, IRefreshTokenStore,IConsentStore服務。更多的信息
的ClientStore的EF-based實現嗎IClientStore接口。 它能夠單獨使用的ScopeStore。
的ScopeStore的EF-based實現嗎IScopeStore接口。 它能夠單獨使用的ClientStore。
使用的商店,他們須要註冊。 上有擴展方法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);
大部分的操做數據已通過期。 極可能須要移除這個陳舊的數據。 能夠承載IdentityServer之外的應用程序或數據庫自己(經過各類機制)。 若是須要你執行這個清理應用程序代碼,那麼TokenCleanup類提供協助。 它接受一個EntityFrameworkServiceOptions和一個Int32時間間隔(以秒爲單位)來配置陳舊的數據清理的頻率。 它將異步鏈接到數據庫,能夠配置爲:
var efConfig = new EntityFrameworkServiceOptions {
ConnectionString = connString,
//Schema = "foo"};
var cleanup = new TokenCleanup(efConfig, 10);cleanup.Start();
IdentityServer3加強,數據庫模式極可能會發生變化。 的預期模式變化,建議(和預期)託管應用程序負責處理這些模式會隨着時間而改變。
實體框架提供了遷移做爲一個方法來處理模式變化和更新您的數據庫與變化。
有三種不一樣的DbContext派生類中包含的EF的實現。 它們是:
l ClientConfigurationDbContext
l ScopeConfigurationDbContext
l OperationalDbContext
這些須要,由於數據庫上下文類(即在一個不一樣的裝配。Thinktecture.IdentityServer3.EntityFramework比託管應用程序)。
遷移必須爲每一個數據庫建立上下文類。 使遷移的全部數據庫上下文類,可使用下面的命令從包管理器控制檯:
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更新到新模式。 檢查英孚文檔爲更多的細節。
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插件對檢索的內置支持從一個內存中的服務依賴方。
看到在這裏
的RelyingParty類模型依賴方:
ws - federation插件包含兩個端點
這是主要的ws - federation端點的簽字。
支持參數:
示例(可讀性編碼刪除):
/wsfed?wa=wsignin1.0&wtrealm=rp1&whr=Google
返回元數據文檔:
/wsfed/metadata
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
l ElasticSearch / Kibana EventService
l 複述,緩存
l OpenID鏈接
l 谷歌
l 推特
l 微軟帳戶
l 臉譜網
l KentorIT認證服務——看到也這博客