IdentityServer4-主題

 1、Startuphtml

2、定義Resources前端

3、定義Clientsnode

4、登陸git

5、使用外部身份提供商登陸github

6、Windows身份驗證web

7、登出數據庫

8、註銷外部身份提供商npm

9、聯合註銷編程

10、聯合網關json

11、Consent

12、保護APIs

十3、部署

十4、日誌

十5、事件

十6、Cryptography, Keys and HTTPS

十7、Grant Types

十8、Secrets

十9、Extension Grants

二10、Resource Owner Password Validation

二11、Refresh Tokens

二12、Reference Tokens

二十3、CORS

二十4、Discovery

二十5、Adding more API Endpoints

二十6、Adding new Protocols

二十7、Tools

 

1、Startup

 IdentityServer是中間件和服務的組合。 全部的配置都在你的startup類上完成。

配置服務

經過調用如下方式將IdentityServer服務添加到DI系統:

public void ConfigureServices(IServiceCollection services)
{
    var builder = services.AddIdentityServer();
}

或者,您能夠將選項傳入此調用。

這將返回一個構建器對象,該構造器對象又有許多方便的方法來鏈接其餘服務。

key材料

  • AddSigningCredential
    添加一個簽名密鑰服務,該服務將指定的密鑰材料提供給各類令牌建立/驗證服務。 您能夠傳入X509Certificate2,SigningCredential或對證書存儲區中證書的引用。
  • AddDeveloperSigningCredential
    在啓動時建立臨時密鑰材料。 當您沒有要使用的證書時,這僅適用於開發場景。 生成的密鑰將保存到文件系統,以便在服務器從新啓動之間保持穩定(可經過傳遞false來禁用)。 這解決了客戶端/ api元數據緩存在開發期間不一樣步的問題。
  • AddValidationKey
    添加驗證令牌的密鑰。 它們將被內部令牌驗證器使用,並將顯示在發現文檔中。 您能夠傳入X509Certificate2,SigningCredential或對證書存儲區中證書的引用。 這對於key的轉換場景頗有用。

In-Memory configuration stores

各類「in-memory」從內存中配置IdentityServer。這些「in-memory」集合能夠在宿主應用程序中進行硬編碼,也能夠從配置文件或數據庫動態加載。 可是,經過設計,這些集合僅在託管應用程序啓動時建立。

使用這些配置API可用於原型設計,開發和或測試時不須要在運行時動態查詢配置數據的數據庫。 若是配置不多發生變化,這種配置方式也適用於生產方案,或者若是必須更改值,則須要從新啓動應用程序並不方便。 

  • AddInMemoryClients
    根據client配置對象的內存中集合註冊IClientStore和ICorsPolicyService實現。
  • AddInMemoryIdentityResources
    基於IdentityResource配置對象的內存中集合註冊IResourceStore實現。
  • AddInMemoryApiResources
    根據ApiResource配置對象的內存集合註冊IResourceStore實現。

Test stores

TestUser類在IdentityServer中爲用戶及其憑據和聲明建模。TestUser的使用與使用「in-memory」存儲相似,由於它適用於原型開發和/或測試。 生產中不推薦使用TestUser。

  • AddTestUsers

     基於TestUser對象的集合註冊TestUserStore。 TestUserStore由默認的快速入門用戶界面使用。 還註冊IProfileService和IResourceOwnerPasswordValidator的實現。

其餘服務

  • AddExtensionGrantValidator
    添加用於擴展受權的IExtensionGrantValidator實現。
  • AddSecretParser
    添加ISecretParser實現以解析客戶端或API資源憑證。
  • AddSecretValidator
    添加ISecretValidator實現,以針對憑證存儲驗證客戶端或API資源憑證。
  • AddResourceOwnerValidator
    添加IResourceOwnerPasswordValidator實現,用於驗證資源全部者密碼憑據受權類型的用戶憑證。
  • AddProfileService
    添加IProfileService實現以鏈接到您的自定義用戶配置文件存儲。 DefaultProfileService類提供了默認實現,它依賴於身份驗證cookie做爲惟一的憑證發放聲明來源。
  • AddAuthorizeInteractionResponseGenerator
    添加IAuthorizeInteractionResponseGenerator實現以在受權端點自定義邏輯,以便必須向用戶顯示錯誤,登陸,贊成或任何其餘自定義頁面的UI。 AuthorizeInteractionResponseGenerator類提供了一個默認的實現,所以若是須要增長現有的行爲,能夠考慮從這個現有的類派生。
  • AddCustomAuthorizeRequestValidator
    添加ICustomAuthorizeRequestValidator實現以在受權端點定製請求參數驗證。
  • AddCustomTokenRequestValidator
    添加ICustomTokenRequestValidator實現來定製令牌端點處的請求參數驗證。
  • AddRedirectUriValidator
    添加IRedirectUriValidator實現來自定義重定向URI驗證。
  • AddAppAuthRedirectUriValidator
    添加一個「AppAuth」(適用於本地應用的OAuth 2.0)兼容的重定向URI驗證器(進行嚴格驗證,但也容許http://127.0.0.1使用隨機端口)。
  • AddJwtBearerClientAuthentication
    添加對使用JWT bearer斷言的客戶端身份驗證的支持。

Caching

客戶端和資源配置數據常常被IdentityServer使用。 若是從數據庫或其餘外部存儲裝載此數據,則常常從新加載相同數據可能會很昂貴。

  • AddInMemoryCaching
    要使用下面描述的任何緩存,必須在DI中註冊ICache <T>的實現。 此API註冊了基於ASP.NET Core的MemoryCache的ICache <T>的默認內存實現。
  • AddClientStoreCache
    註冊IClientStore裝飾器實現,該實現將維護客戶端配置對象的內存緩存。 能夠在IdentityServerOptions上的Cachingconfiguration選項上配置緩存持續時間。
  • AddResourceStoreCache
    註冊一個IResourceStore裝飾器實現,它將維護IdentityResource和ApiResource配置對象的內存緩存。 緩存持續時間能夠在IdentityServerOptions上的緩存配置選項上配置。
  • AddCorsPolicyCache
    註冊一個ICorsPolicyService裝飾器實現,它將維護CORS策略服務評估結果的內存緩存。 緩存持續時間能夠在IdentityServerOptions上的緩存配置選項上配置。

進一步定製緩存是可能的:

默認緩存依賴於ICache <T>實現。 若是您但願爲特定配置對象定製緩存行爲,則能夠在依賴注入系統中替換此實現。

Cache <T>自己的默認實現依賴於.NET提供的IMemoryCache接口(和MemoryCache實現)。 若是您但願自定義內存中緩存行爲,則能夠替換依賴注入系統中的IMemoryCache實現。

配置管道

您須要經過調用如下方式將IdentityServer添加到管道中:

public void Configure(IApplicationBuilder app)
{
    app.UseIdentityServer();
}

UseIdentityServer包含對UseAuthentication的調用,因此沒有必要同時擁有二者。

沒有額外的中間件配置。

請注意,管道的順序中很重要。 例如,您須要在實現登陸屏幕的UI框架以前添加IdentitySever。

 

2、定義Resources

您一般在系統中定義的第一件事是您要保護的資源。 這多是用戶的身份信息,例如我的資料數據或電子郵件地址,或訪問API。 

定義identity resources

identity resources是數據,如用戶ID,姓名或用戶的電子郵件地址。 身份資源具備惟一的名稱,您能夠爲其分配任意聲明類型。 這些聲明將包含在用戶的身份標識中。 客戶端將使用scope參數來請求訪問身份資源。

OpenID Connect規範指定了幾個標準身份資源。 最低要求是,您提供了爲用戶發佈惟一ID的支持 - 也稱爲subject id。 這是經過暴露名爲openid的標準身份資源完成的:

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId()
    };
}

IdentityResources類支持規範中定義的全部範圍(openid,電子郵件,配置文件,電話和地址)。 若是您想所有支持它們,能夠將它們添加到支持的身份資源列表中:

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Email(),
        new IdentityResources.Profile(),
        new IdentityResources.Phone(),
        new IdentityResources.Address()
    };
}

自定義identity resources

您還能夠自定義標識資源。 建立一個新的IdentityResource類,給它一個名稱和一個可選的顯示名稱和描述,並在請求此資源時定義哪些用戶聲明應該包含在身份令牌中:

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    var customProfile = new IdentityResource(
        name: "custom.profile",
        displayName: "Custom profile",
        claimTypes: new[] { "name", "email", "status" });

    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        customProfile
    };
}

定義API resources

爲了容許客戶端請求API的訪問令牌,您須要定義API資源,例如:

要獲取API的訪問令牌,還須要將它們註冊爲scope。 此次scope類型是Resource類型的:

public static IEnumerable<ApiResource> GetApis()
{
    return new[]
    {
        // 簡單的API與單一scope(在這種狀況下,scope名稱與api名稱相同)
        new ApiResource("api1", "Some API 1"),

        // 若是須要更多的控制,擴展版本
        new ApiResource
        {
            Name = "api2",

            // secret for using introspection endpoint
            ApiSecrets =
            {
                new Secret("secret".Sha256())
            },

            // 在訪問令牌中包含如下使用聲明(除了subject ID)
            UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.Email },

            //此API定義了兩個scope
            Scopes =
            {
                new Scope()
                {
                    Name = "api2.full_access",
                    DisplayName = "Full access to API 2",
                },
                new Scope
                {
                    Name = "api2.read_only",
                    DisplayName = "Read only access to API 2"
                }
            }
        }
    };
}

 

3、定義Clients

客戶端表明能夠從您的身份服務器請求令牌的應用程序。

細節有所不一樣,但您一般爲客戶端定義如下經常使用設置:

  • 一個惟一的client ID
  • secret 若是須要的話
  • 容許的與令牌服務的交互(稱爲受權類型)
  • 身份和/或訪問令牌發送到的網絡位置(稱爲重定向URI)
  • 客戶端容許訪問的範圍列表(又名資源)

定義服務器到服務器通訊的客戶端

在這種狀況下,不存在交互用戶—服務(又稱客戶端)但願與API(又稱範圍)進行通訊:

public class Clients
{
    public static IEnumerable<Client> Get()
    {
        return new List<Client>
        {
            new Client
            {
                ClientId = "service.client",
                ClientSecrets = { new Secret("secret".Sha256()) },

                AllowedGrantTypes = GrantTypes.ClientCredentials,
                AllowedScopes = { "api1", "api2.read_only" }
            }
        };
    }
}

定義基於瀏覽器的JavaScript客戶端(例如SPA)以進行用戶身份驗證和委派訪問以及API

該客戶端使用所謂的隱式流來從JavaScript請求身份和訪問令牌:

var jsClient = new Client
{
    ClientId = "js",
    ClientName = "JavaScript Client",
    ClientUri = "http://identityserver.io",

    AllowedGrantTypes = GrantTypes.Implicit,
    AllowAccessTokensViaBrowser = true,

    RedirectUris =           { "http://localhost:7017/index.html" },
    PostLogoutRedirectUris = { "http://localhost:7017/index.html" },
    AllowedCorsOrigins =     { "http://localhost:7017" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,

        "api1", "api2.read_only"
    }
};

定義服務器端Web應用程序(例如MVC)以使用身份驗證和委派API訪問

交互式服務器端(或本地桌面/移動)應用程序使用混合流。 此流提供了最佳的安全性,由於訪問令牌僅經過後通道調用傳輸(並容許您訪問refresh令牌)::

var mvcClient = new Client
{
    ClientId = "mvc",
    ClientName = "MVC Client",
    ClientUri = "http://identityserver.io",

    AllowedGrantTypes = GrantTypes.Hybrid,
    AllowOfflineAccess = true,
    ClientSecrets = { new Secret("secret".Sha256()) },

    RedirectUris =           { "http://localhost:21402/signin-oidc" },
    PostLogoutRedirectUris = { "http://localhost:21402/" },
    FrontChannelLogoutUri =  "http://localhost:21402/signout-oidc",

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,

        "api1", "api2.read_only"
    },
};

 

4、登陸

 爲了讓IdentityServer表明用戶發出令牌,該用戶必須登陸到IdentityServer。

Cookie身份驗證

使用來自ASP.NET Core的cookie身份驗證處理程序管理的cookie跟蹤身份驗證。

IdentityServer註冊兩個cookie處理程序(一個用於身份驗證會話,另外一個用於臨時的外部cookie)。 這些是默認使用的,若是要手動引用它們,能夠從IdentityServerConstants類(DefaultCookieAuthenticationScheme和ExternalCookieAuthenticationScheme)獲取它們的名稱。

咱們只公開這些cookie的基本設置(到期和滑動),若是您須要更多控制,您能夠註冊本身的cookie處理程序。 當使用ASP.NET Core中的AddAuthentication時,IdentityServer使用與AuthenticationOptions上配置的任何cookie處理程序匹配的DefaultAuthenticateScheme。

重寫cookie處理程序配置

若是您但願使用本身的cookie身份驗證處理程序,則必須本身配置它。 在DI(使用AddIdentityServer)註冊IdentityServer後,必須在ConfigureServices中完成此操做。 例如:

services.AddIdentityServer()
    .AddInMemoryClients(Clients.Get())
    .AddInMemoryIdentityResources(Resources.GetIdentityResources())
    .AddInMemoryApiResources(Resources.GetApiResources())
    .AddDeveloperSigningCredential()
    .AddTestUsers(TestUsers.Users);

services.AddAuthentication("MyCookie")
    .AddCookie("MyCookie", options =>
    {
        options.ExpireTimeSpan = ...;
    });

IdentityServer內部使用自定義方案(經過常量IdentityServerConstants.DefaultCookieAuthenticationScheme)調用AddAuthentication和AddCookie,所以要覆蓋它們,必須在AddIdentityServer以後進行相同的調用。

登陸用戶界面和身份管理系統

IdentityServer不爲用戶認證提供任何用戶界面或用戶數據庫。 這些是您但願本身提供或開發的東西。

若是您須要基本UI的起點(登陸,註銷,贊成和管理受權),您可使用咱們的quickstart UI.

快速啓動用戶界面根據內存數據庫對用戶進行身份驗證。 您能夠經過訪問真實用戶存儲來替換這些位。 咱們有使用ASP.NET Identity的示例。

登陸工做流程

當IdentityServer在受權端點收到請求而且用戶未經過身份驗證時,用戶將被重定向到配置的登陸頁面。 您必須經過選項上的UserInteraction設置(默認爲/ account/login)來通知IdentityServer您的登陸頁面的路徑。 將傳遞returnUrl參數,通知您的登陸頁面,一旦登陸完成,應該重定向用戶。

            services.AddIdentityServer(options=>{
                options.UserInteraction.LoginUrl="/Identity/Account/Login";
            })
                    .AddDeveloperSigningCredential()
                    .AddInMemoryPersistedGrants()
                    .AddInMemoryApiResources(Config.GetApiResource())
                    .AddInMemoryIdentityResources(Config.GetIdentityResource())
                    .AddInMemoryClients(Config.GetClient())
                    .AddAspNetIdentity<IdentityUser>();
重定向登陸頁面

登陸上下文

在您的登陸頁面上,您可能須要有關請求上下文的信息,以便自定義登陸體驗(如客戶端,提示參數,IdP提示或其餘內容)。 這能夠經過交互服務上的GetAuthorizationContextAsync API獲取。

發佈cookie和聲明 

在ASP.NET Core的HttpContext上有與身份驗證相關的擴展方法來發布身份驗證cookie並簽署用戶身份。所使用的身份驗證方案必須與您正在使用的cookie處理程序匹配(請參閱上文)。

當您在用戶中籤名時,您必須發出至少一個子claim和一個名稱claim。IdentityServer還在HttpContext上提供一些SignInAsync擴展方法,使其更加方便。

您還能夠選擇發出idp聲明(用於身份提供者名稱),amr聲明(用於所使用的身份驗證方法)和/或auth_time聲明(用於用戶驗證的紀元時間)。 若是您不提供這些,IdentityServer將提供默認值。

 

5、使用外部身份提供商登陸

ASP.NET Core具備處理外部認證的靈活方式。 這涉及幾個步驟。

爲外部提供者添加認證處理程序

與外部提供者通訊所需的協議實現封裝在身份驗證處理程序中。 一些提供商使用專有協議(例如Facebook等社交提供商),有些提供商使用標準協議,例如 OpenID Connect,WS-Federation或SAML2p。

Cookie的做用

外部認證處理程序上的一個選項稱爲SignInScheme,例如:

services.AddAuthentication()
    .AddGoogle("Google", options =>
    {
        options.SignInScheme = "scheme of cookie handler to use";

        options.ClientId = "...";
        options.ClientSecret = "...";
    })

登陸方案指定將臨時存儲外部認證結果的cookie處理程序的名稱,例如 這獲得了由外部供應商發來的聲明。 這是必要的,由於在完成外部認證過程以前,一般會有幾個重定向。

鑑於這是一種常見作法,IdentityServer專門爲此外部提供程序工做流程註冊一個Cookie處理程序。 該方案經過IdentityServerConstants.ExternalCookieAuthenticationScheme常量表示。 若是您要使用咱們的外部cookie處理程序,那麼對於上面的SignInScheme,您將分配的值爲IdentityServerConstants.ExternalCookieAuthenticationScheme常量:

services.AddAuthentication()
    .AddGoogle("Google", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

        options.ClientId = "...";
        options.ClientSecret = "...";
    })

您也能夠註冊本身的自定義cookie處理程序,以下所示:

services.AddAuthentication()
    .AddCookie("YourCustomScheme")
    .AddGoogle("Google", options =>
    {
        options.SignInScheme = "YourCustomScheme";

        options.ClientId = "...";
        options.ClientSecret = "...";
    })

觸發認證處理程序

您能夠經過HttpContext上的ChallengeAsync擴展方法(或使用MVC ChallengeResult)調用外部認證處理程序。

您一般但願將一些選項傳遞給challenge操做,例如回調頁面的路徑和簿記提供程序的名稱,例如:

var callbackUrl = Url.Action("ExternalLoginCallback");

var props = new AuthenticationProperties
{
    RedirectUri = callbackUrl,
    Items =
    {
        { "scheme", provider },
        { "returnUrl", returnUrl }
    }
};

return Challenge(provider, props);

處理回調並在用戶中籤名

在回調頁面上,您的典型任務是:

  • 檢查由外部提供商返回的身份。
  • 決定如何處理該用戶。 若是這是新用戶或返回用戶,這可能會有所不一樣。
  • 新用戶在容許以前可能須要額外的步驟和UI。
  • 可能會建立一個連接到外部提供程序的新內部用戶賬戶。
  • 存儲您想要保留的外部聲明。
  • 刪除臨時cookie
  • 登陸用戶

檢查外部身份:

// 從臨時cookie中讀取外部身份
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
if (result?.Succeeded != true)
{
    throw new Exception("External authentication error");
}

//檢索外部用戶的聲明
var externalUser = result.Principal;
if (externalUser == null)
{
    throw new Exception("External authentication error");
}

// 檢索外部用戶的聲明
var claims = externalUser.Claims.ToList();

// 嘗試肯定外部用戶的惟一ID - 最多見的聲明類型是子聲明和NameIdentifier
// 根據外部提供商,可能會使用其餘一些聲明類型
var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
if (userIdClaim == null)
{
    userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
}
if (userIdClaim == null)
{
    throw new Exception("Unknown userid");
}

var externalUserId = userIdClaim.Value;
var externalProvider = userIdClaim.Issuer;

// 使用externalProvider和externalUserId查找您的用戶,或者配置新用戶

清理和登陸:

//爲用戶發佈身份驗證Cookie
await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, props, additionalClaims.ToArray());

// 刪除外部認證期間使用的臨時cookie
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

// 驗證返回URL並重定向回受權端點或本地頁面
if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
{
    return Redirect(returnUrl);
}

return Redirect("~/");

狀態,URL長度和ISecureDataFormat

 當重定向到外部提供商登陸時,客戶端應用程序中的頻繁狀態必須進行往返。 這意味着狀態在離開客戶端以前被捕獲並保存直到用戶返回到客戶端應用程序。 包括OpenID Connect在內的許多協議都容許將某種狀態做爲參數傳遞,做爲請求的一部分,身份提供者將在響應中返回該狀態。 ASP.NET Core提供的OpenID Connect身份驗證處理程序利用了協議的這一功能,這就是它如何實現上面提到的returnUrl功能。

在請求參數中存儲狀態的問題是請求URL可能會變得太大(超過2000個字符的公共限制)。 OpenID Connect身份驗證處理程序的確提供了一個可擴展點,以便將狀態存儲在服務器中,而不是存儲在請求URL中。 你能夠經過實現ISecureDataFormat <AuthenticationProperties>並在OpenIdConnectOptions上配置它來實現這一點。

幸運的是,IdentityServer爲您提供了一個實現,並由在DI容器中註冊的IDistributedCache實現(例如標準MemoryDistributedCache)支持。 要使用IdentityServer提供的安全數據格式實現,只需在配置DI時在IServiceCollection上調用AddOidcStateDataFormatterCache擴展方法便可。 若是沒有參數傳遞,則全部配置的OpenID Connect處理程序將使用IdentityServer提供的安全數據格式實現:

public void ConfigureServices(IServiceCollection services)
{
    // 配置OpenIdConnect處理程序以將狀態參數保存到服務器端的IDistributedCache中。
    services.AddOidcStateDataFormatterCache();

    services.AddAuthentication()
        .AddOpenIdConnect("demoidsrv", "IdentityServer", options =>
        {
            // ...
        })
        .AddOpenIdConnect("aad", "Azure AD", options =>
        {
            // ...
        })
        .AddOpenIdConnect("adfs", "ADFS", options =>
        {
            // ...
        });
}

若是隻配置特定方案,則將這些方案做爲參數傳遞:

public void ConfigureServices(IServiceCollection services)
{
    //配置OpenIdConnect處理程序以將狀態參數保存到服務器端的IDistributedCache中。
    services.AddOidcStateDataFormatterCache("aad", "demoidsrv");

    services.AddAuthentication()
        .AddOpenIdConnect("demoidsrv", "IdentityServer", options =>
        {
            // ...
        })
        .AddOpenIdConnect("aad", "Azure AD", options =>
        {
            // ...
        })
        .AddOpenIdConnect("adfs", "ADFS", options =>
        {
            // ...
        });
}

 

 

6、Windows身份驗證

在支持的平臺上,您可使用IdentityServer使用Windows身份驗證(例如,針對Active Directory)對用戶進行身份驗證。 當前使用如下命令託管IdentityServer時,Windows身份驗證可用: 

  • 使用IIS和IIS集成包在Windows上使用Kestrel
  • Windows上的HTTP.sys服務器

在這兩種狀況下,使用方案「Windows」在HttpContext上使用ChallengeAsync API來觸發Windows身份驗證。 咱們的快速入門UI中的賬戶控制器實現了必要的邏輯。
Using Kestrel

使用Kestrel時,必須運行「behind」IIS並使用IIS integration:

var host = new WebHostBuilder()
    .UseKestrel()
    .UseUrls("http://localhost:5000")
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();

在使用WebHost.CreateDefaultBuilder方法設置WebHostBuilder時,Kestrel會自動配置。

此外,IIS(或IIS Express)中的虛擬目錄必須啓用Windows和匿名身份驗證。

IIS集成層將Windows身份驗證處理程序配置爲DI,能夠經過身份驗證服務調用。 一般在IdentityServer中,建議禁用此自動行爲。 這在ConfigureServices中完成:

services.Configure<IISOptions>(iis =>
{
    iis.AuthenticationDisplayName = "Windows";
    iis.AutomaticAuthentication = false;
});

 

7、登出

註銷IdentityServer就像刪除身份驗證cookie同樣簡單,可是爲了完成聯合註銷,咱們必須考慮將用戶從客戶端應用程序(甚至多是上游身份提供商)中註銷。 

刪除身份驗證Cookie

要刪除身份驗證cookie,只需在HttpContext上使用SignOutAsync擴展方法便可。 您將須要傳遞使用的方案(由IdentityServerConstants.DefaultCookieAuthenticationScheme提供,除非您已更改它):

await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);

或者您可使用IdentityServer提供的便捷擴展方法:

await HttpContext.SignOutAsync();

通知客戶該用戶已註銷

做爲註銷過程的一部分,您須要確保向客戶端應用程序通知用戶已註銷。 IdentityServer支持服務器端客戶端(例如MVC)的前端通道規範,服務器端客戶端的後端通道規範(例如MVC)以及基於瀏覽器的JavaScript客戶端的會話管理規範(例如SPA,React,Angular 等)。

前端服務器端客戶端

要經過前端通道規範從服務器端客戶端應用程序註銷用戶,IdentityServer中的「註銷」頁面必須呈現<iframe>以通知客戶端用戶已註銷。 但願被通知的客戶端必須設置FrontChannelLogoutUri配置值。 IdentityServer跟蹤用戶登陸的客戶端,並在IIdentityServerInteractionService(詳細信息)上提供名爲GetLogoutContextAsync的API。 該API返回一個帶有SignOutIFrameUrl屬性的LogoutRequest對象,您註銷的頁面必須呈現爲<iframe>。

後端服務器端客戶端

要經過後端通道規範從服務器端客戶端應用程序註銷用戶,IdentityServer中的SignOutIFrameUrl端點將自動觸發服務器到服務器的調用,將簽名註銷請求傳遞給客戶端。 這意味着即便沒有前端通道客戶端,IdentityServer中的「註銷」頁面也必須如上所述向SignOutIFrameUrl呈現<iframe>。 但願收到通知的客戶端必須設置BackChannelLogoutUri配置值。

基於瀏覽器的JavaScript客戶端

鑑於會話管理規範的設計方式,IdentityServer中沒有什麼特別的,您須要作的是通知這些客戶端用戶已註銷。 可是,客戶端必須對check_session_iframe執行監視,而且這由oidc-client JavaScript庫實現。

由客戶端應用程序發起的註銷

若是註銷是由客戶端應用程序啓動的,則客戶端首先將用戶重定向到最終會話端點。 在會話結束端點進行處理可能須要經過重定向到註銷頁面來維護一些臨時狀態(例如,客戶端的註銷註銷重定向uri)。 該狀態可能對註銷頁面有用,而且狀態的標識符經過logoutId參數傳遞到註銷頁面。

交互服務上的GetLogoutContextAsync API可用於加載狀態。ShowSignoutPrompt指示註銷請求是否已經過身份驗證, 所以不會提示用戶註銷。

默認狀況下,此狀態做爲經過logoutId值傳遞的受保護數據結構進行管理。 若是您但願在終端會話終端和註銷頁面之間使用其餘持久性,則能夠實現IMessageStore <LogoutMessage>並在DI中註冊實現。

 

8、註銷外部身份提供商

當用戶註銷IdentityServer,而且他們使用外部身份提供程序登陸時,可能會將其重定向到也註銷外部提供程序。 並不是全部外部提供商都支持註銷,由於它取決於它們支持的協議和功能。

要檢測用戶必須重定向到外部身份提供者進行註銷,一般經過在IdentityServer中使用發佈到cookie中的idp聲明來完成。 此聲明中設置的值是相應身份驗證中間件的AuthenticationScheme。 在註銷時,諮詢此聲明以瞭解是否須要外部註銷。 

歸因於正常註銷工做流程已經須要的清理和狀態管理,將用戶重定向至外部身份提供者是有問題的。 而後在IdentityServer上完成正常註銷和清除過程的惟一方法是,而後向外部身份提供者請求在註銷後將用戶重定向回IdentityServer。 並不是全部外部提供商都支持註銷後重定向,由於它取決於它們支持的協議和功能。

而後,註銷時的工做流程將撤消IdentityServer的身份驗證cookie,而後重定向到請求退出後重定向的外部提供程序。 註銷後重定向應保持此處所述的必要註銷狀態(即logoutId參數值)。 要在外部提供者註銷後重定向到IdentityServer,在使用ASP.NET Core的SignOutAsync API時,應在AuthenticationProperties上使用RedirectUri,例如:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
    // 構建模型,以便註銷頁面知道要顯示的內容
    var vm = await _account.BuildLoggedOutViewModelAsync(model.LogoutId);

    var user = HttpContext.User;
    if (user?.Identity.IsAuthenticated == true)
    {
        // 刪除本地認證cookie
        await HttpContext.SignOutAsync();

        // 喚起註銷事件
        await _events.RaiseAsync(new UserLogoutSuccessEvent(user.GetSubjectId(), user.GetName()));
    }

    //檢查咱們是否須要在上游身份提供商處觸發註銷
    if (vm.TriggerExternalSignout)
    {
        // 創建一個返回URL,以便上游提供商將重定向回來
        // 在用戶註銷後給咱們。 這可讓咱們接下來
        // 完成咱們的單一註銷處理。
        string url = Url.Action("Logout", new { logoutId = vm.LogoutId });

        // 這會觸發重定向到外部提供程序以進行註銷
        return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
    }

    return View("LoggedOut", vm);
}

一旦用戶註銷外部提供者而後重定向,IdentityServer的正常註銷處理應該執行,其中涉及處理logoutId並進行全部必要的清理。

9、聯合註銷

 聯合註銷是指用戶使用外部身份提供程序登陸身份服務器的狀況,而後,用戶經過身份服務器未知的工做流注銷該外部標識提供者。當用戶註銷時,通知身份服務器將很是有用,這樣它就能夠將用戶從標識服務器和全部使用標識服務器的應用程序中註銷。

並不是全部外部身份提供者都支持聯合註銷,可是那些這樣作的人將提供一種機制來通知客戶端用戶已經註銷了。此通知一般以來自外部身份提供者的「註銷」頁面的<iframe>請求的形式出現。而後,IdentityServer必須通知其全部客戶端(如此處所述),一般還要從外部身份提供者的<iframe>中以<iframe>的形式發送請求。

使聯合註銷成爲特殊狀況(與正常註銷相比)的緣由是聯合註銷請求不是IdentityServer中的正常註銷端點。 事實上,每一個外部IdentityProvider將在您的IdentityServer主機中具備不一樣的端點。 這是由於每一個外部身份提供者可能使用不一樣的協議,而且每一箇中間件都在不一樣的端點上偵聽。 

全部這些因素的淨效應是,沒有像咱們在正常註銷工做流程中那樣呈現「註銷」頁面,這意味着咱們錯過了IdentityServer客戶端的註銷通知。 咱們必須爲每一個這些聯合註銷端點添加代碼,以呈現必要的通知以實現聯合註銷。

幸運的是,IdentityServer已經包含此代碼。 當請求進入IdentityServer並調用外部認證提供程序的處理程序時,IdentityServer會檢測這些聯合註銷請求是否爲聯合註銷請求,若是是,它將自動呈現與此處所述的相同的<iframe>用於註銷。 簡而言之,自動支持聯合註銷。

 

10、聯合網關

通用架構是所謂的聯合網關。 在這種方法中,IdentityServer充當一個或多個外部身份提供者的網關。

該架構具備如下優勢

  • 你的應用程序只須要知道一個令牌服務(網關),而且不須要關於鏈接到外部提供者的全部細節。 這也意味着您能夠添加或更改這些外部提供程序,而無需更新您的應用程序。
  • 您控制網關(而不是某些外部服務提供商) - 這意味着您能夠對其進行任何更改,並保護您的應用程序免受外部提供程序可能對其本身的服務所作的更改。

  • 大多數外部提供商僅支持一組固定的聲明和聲明類型 - 在中間具備網關容許對提供商的響應進行後處理以轉換/添加/修改特定於域的身份信息。
  • 某些提供商不支持訪問令牌(例如社交提供商) - 由於網關知道您的API,它能夠根據外部身份發出訪問令牌。
  • 有些提供商會根據您鏈接到的應用程序的數量收費。 網關充當外部提供程序的單個應用程序。 在內部,您能夠根據須要鏈接任意數量的應用程序。
  • 一些提供商使用專有協議或對標準協議進行專有修改 - 對於網關,您只須要處理一個地方。
  • 強制每一個身份驗證(內部或外部)經過一個地方爲身份映射提供極大的靈活性,爲您的全部應用程序提供穩定的身份並處理新的需求

換句話說 - 擁有您的聯合網關可讓您對您的身份基礎架構進行不少控制。 因爲您的用戶身份是您最重要的資產之一,咱們建議您控制網關。

咱們的快速入門UI使用瞭如下一些功能。 還請查看外部認證快速入門和有關外部提供商的文檔。

  • 您能夠經過向IdentityServer應用程序添加身份驗證處理程序來添加對外部身份提供程序的支持。
  • 您能夠經過調用IAuthenticationSchemeProvider以編程方式查詢這些外部提供程序。 這容許根據註冊的外部提供商動態呈現您的登陸頁面。
  • 咱們的客戶端配置模型容許以每一個客戶端爲基礎限制可用的提供者(使用IdentityProviderRestrictions屬性)。
  • 您也可使用客戶端上的EnableLocalLogin屬性來告訴您的UI是否應呈現用戶名/密碼輸入。
  • 咱們的快速入門用戶界面經過單個回調來引導全部外部認證調用(請參閱AccountController類中的ExternalLoginCallback)。 這容許單點進行後處理。

 

11、Consent

在受權請求期間,若是IdentityServer須要用戶贊成,則瀏覽器將被重定向到贊成頁面。 

贊成用於容許最終用戶授予客戶端對資源(身份或API)的訪問權限。 這一般只對第三方客戶端是必需的,而且能夠在客戶端設置上對每一個客戶端啓用/禁用。

Consent頁面

爲了讓用戶贊成,託管應用程序必須提供贊成頁面。 快速入門UI具備贊成頁面的基本實現。

贊成頁面一般呈現當前用戶的顯示名稱,請求訪問的客戶端的顯示名稱,客戶端的徽標,有關客戶端的更多信息的連接以及客戶端請求訪問的資源列表。 容許用戶代表他們的贊成應該被「記住」,以便未來不會再爲相同的客戶再次提示他們也是常見的。

一旦用戶提供了贊成,贊成頁面必須通知IdentityServer贊成,而後瀏覽器必須重定向回受權端點。

受權上下文

IdentityServer將傳遞一個returnUrl參數(可在用戶交互選項上配置)到包含受權請求參數的贊成頁面。 這些參數提供了贊成頁面的上下文,而且能夠在交互服務的幫助下閱讀。 GetAuthorizationContextAsync API將返回AuthorizationRequest的一個實例。

可使用IClientStore和IResourceStore接口獲取有關客戶端或資源的其餘詳細信息。

向IdentityServer通知贊成結果

交互服務上的GrantConsentAsync API容許贊成頁面通知IdentityServer贊成的結果(也多是拒絕客戶端訪問)。

IdentityServer將暫時持久贊成的結果。 這個持久性默認使用cookie,由於它只需保存足夠長的時間以將結果傳遞迴受權端點。 此臨時持久性與用於「記住個人贊成」功能的持久性不一樣(而且它是持久存儲用戶的「記住個人贊成」的受權端點)。 若是您但願在許可頁面和受權重定向之間使用其餘持久性,則能夠實現IMessageStore <ConsentResponse>並在DI中註冊實現。

將用戶返回到受權端點

一旦贊成頁面通知了IdentityServer的結果,用戶能夠被重定向回returnUrl。 您的贊成頁面應經過驗證returnUrl是否有效來防止打開重定向。 這能夠經過在交互服務上調用IsValidReturnUrl來完成。 此外,若是GetAuthorizationContextAsync返回非null結果,那麼您還能夠信任returnUrl有效。

 

12、保護APIs

IdentityServer默認以JWT(JSON Web令牌)格式發出訪問令牌。 

今天的每一個相關平臺都支持驗證JWT令牌,這裏能夠找到一個很好的JWT庫列表:

保護基於ASP.NET Core的API只是在DI中配置JWT承載身份驗證處理程序,並將身份驗證中間件添加到管道:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                // base-address of your identityserver
                options.Authority = "https://demo.identityserver.io";

                // name of the API resource
                options.Audience = "api1";
            });
    }

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
        app.UseAuthentication();
        app.UseMvc();
    }
}

IdentityServer身份驗證處理程序

咱們的身份驗證處理程序與上述處理程序具備相同的用途(實際上它在內部使用Microsoft JWT庫),但添加了一些附加功能:

  • 支持JWTs和引用令牌
  • 用於引用標記的可擴展緩存
  • 統一配置模型
  • scope驗證

對於最簡單的狀況,咱們的處理程序配置與上面的代碼片斷很是類似:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
            .AddIdentityServerAuthentication(options =>
            {
                // base-address of your identityserver
                options.Authority = "https://demo.identityserver.io";

                // name of the API resource
                options.ApiName = "api1";
            });
    }

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
        app.UseAuthentication();
        app.UseMvc();
    }
}

支持參考標記

若是傳入令牌不是JWT,咱們的中間件將調用在發現文檔中找到的自省端點以驗證該令牌。 因爲自檢端點須要身份驗證,所以您須要提供已配置的API secret,例如:

.AddIdentityServerAuthentication(options =>
{
    // base-address of your identityserver
    options.Authority = "https://demo.identityserver.io";

    // name of the API resource
    options.ApiName = "api1";
    options.ApiSecret = "secret";
})

一般,您不但願爲每一個傳入請求執行自檢端點的往返。 中間件有一個內置緩存,您能夠像這樣啓用:

.AddIdentityServerAuthentication(options =>
{
    // base-address of your identityserver
    options.Authority = "https://demo.identityserver.io";

    // name of the API resource
    options.ApiName = "api1";
    options.ApiSecret = "secret";

    options.EnableCaching = true;
    options.CacheDuration = TimeSpan.FromMinutes(10); // that's the default
})

處理程序將使用DI容器中註冊的任何IDistributedCache實現(例如,標準MemoryDistributedCache)。

驗證scopes

ApiName屬性檢查令牌是否具備匹配的受衆(或短審計)聲明。

在IdentityServer中,您還能夠將API細分爲多個範圍。 若是您須要這種粒度,則可使用ASP.NET Core受權策略系統來檢查範圍。

制定全局政策:

services
    .AddMvcCore(options =>
    {
        // require scope1 or scope2
        var policy = ScopePolicy.Create("scope1", "scope2");
        options.Filters.Add(new AuthorizeFilter(policy));
    })
    .AddJsonFormatters()
    .AddAuthorization();

撰寫範圍政策:

services.AddAuthorization(options =>
{
    options.AddPolicy("myPolicy", builder =>
    {
        // require scope1
        builder.RequireScope("scope1");
        // and require scope2 or scope3
        builder.RequireScope("scope2", "scope3");
    });
});

 

十3、部署

您的身份服務器只是一個標準的ASP.NET核心應用程序,包括IdentityServer中間件。 首先閱讀有關發佈和部署的官方Microsoft文檔。 

您的典型架構

一般,您將設計IdentityServer部署以實現高可用性:

IdentityServer自己是無狀態的,不須要服務器關聯 - 可是有些數據須要在實例之間共享。

配置數據 

這一般包括:

  • resources
  • clients
  • startup配置

存儲數據的方式取決於您的環境。 在配置數據不多更改的狀況下,咱們建議使用內存存儲和代碼或配置文件。

在高度動態的環境(例如Saas)中,咱們建議使用數據庫或配置服務動態加載配置。

IdentityServer支持代碼配置和配置文件(請參閱此處)。 對於數據庫,咱們爲基於Entity Framework Core的數據庫提供支持。

您還能夠經過實現IResourceStore和IClientStore來構建本身的配置存儲。

Key material

參考:https://identityserver4.readthedocs.io/en/release/topics/crypto.html#refcrypto

運營數據

對於某些操做,IdentityServer須要持久性存儲來保持狀態,這包括:

  • 發佈受權碼
  • 發出引用和刷新令牌
  • 存儲贊成

您可使用傳統數據庫來存儲運營數據,也可使用具備持久性功能(如Redis)的緩存。 上面提到的EF核心實施也支持運營數據。

您也能夠經過實施IPersistedGrantStore來實現對自定義存儲機制的支持 - 默認狀況下IdentityServer會注入內存中的版本。

ASP.NET core數據保護

ASP.NET Core自己須要共享key material來保護cookie,狀態字符串等敏感數據。請參閱此處的官方文檔。

您能夠重複使用上述持久性存儲之一,也可使用像共享文件這樣的簡單文件。

 

十4、日誌

IdentityServer使用ASP.NET Core提供的標準日誌記錄工具。 Microsoft文檔有一個很好的介紹和內置日誌記錄提供程序的說明。 

咱們大體遵循Microsoft使用日誌級別的準則:

  • Trace 僅供開發人員解決問題的信息。 這些消息可能包含敏感的應用程序數據(如令牌),不該在生產環境中啓用。
  • Debug 遵循內部流程並理解爲何作出某些決定。 在開發和調試過程當中有短時間的用處。
  • Information 用於跟蹤應用程序的通常流程。 這些日誌一般具備一些長期價值。
  • Warning針對應用程序流程中的異常或意外事件。 這些可能包括錯誤或其餘不會致使應用程序中止的狀況,但可能須要進行調查。
  • Error 對於沒法處理的錯誤和異常。 示例:協議請求的驗證失敗。
  • Critical對於須要當即關注的故障。 示例:缺乏商店實施,無效的key material......

Serilog的設置

https://serilog.net/

ASP.NET Core 2.0+

對於如下配置,您須要Serilog.AspNetCore和Serilog.Sinks.Console包:

public class Program
{
    public static void Main(string[] args)
    {
        Console.Title = "IdentityServer4";

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .MinimumLevel.Override("System", LogEventLevel.Warning)
            .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
            .Enrich.FromLogContext()
            .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate)
            .CreateLogger();

        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args)
    {
        return WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseSerilog()
                .Build();
    }
}

 

十5、事件

日誌記錄是更低級別的「printf」樣式 - 事件表明有關IdentityServer中某些操做的更高級別信息。 事件是結構化數據,包括事件ID,成功/失敗信息,類別和詳細信息。 這使查詢和分析它們變得很容易,並提取可用於進一步處理的有用信息。

Events work great with event stores like ELKSeq or Splunk.

發出事件

默認狀況下不會啓用事件 - 但能夠在ConfigureServices方法中全局配置,例如:

services.AddIdentityServer(options =>
{
    options.Events.RaiseSuccessEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseErrorEvents = true;
});

要發出一個事件,請使用DI容器中的IEventService並調用RaiseAsync方法,例如:

public async Task<IActionResult> Login(LoginInputModel model)
{
    if (_users.ValidateCredentials(model.Username, model.Password))
    {
        // issue authentication cookie with subject ID and username
        var user = _users.FindByUsername(model.Username);
        await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username));
    }
    else
    {
        await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));
    }
}

自定義sinks

咱們的默認事件接收器將簡單地將事件類序列化爲JSON並將其轉發給ASP.NET Core日誌記錄系統。 若是要鏈接到自定義事件存儲,請實現IEventSink接口並將其註冊到DI。

如下示例使用Seq發出事件:

public class SeqEventSink : IEventSink
{
    private readonly Logger _log;

    public SeqEventSink()
    {
        _log = new LoggerConfiguration()
            .WriteTo.Seq("http://localhost:5341")
            .CreateLogger();
    }

    public Task PersistAsync(Event evt)
    {
        if (evt.EventType == EventTypes.Success ||
            evt.EventType == EventTypes.Information)
        {
            _log.Information("{Name} ({Id}), Details: {@details}",
                evt.Name,
                evt.Id,
                evt);
        }
        else
        {
            _log.Error("{Name} ({Id}), Details: {@details}",
                evt.Name,
                evt.Id,
                evt);
        }

        return Task.CompletedTask;
    }
}

將Serilog.Sinks.Seq包添加到主機以使上述代碼生效。

內置事件

IdentityServer中定義瞭如下事件:

ApiAuthenticationFailureEvent & ApiAuthenticationSuccessEvent

獲取用於在自檢端點進行成功/失敗的API身份驗證。

ClientAuthenticationSuccessEvent & ClientAuthenticationFailureEvent

獲取令牌端點上的成功/失敗客戶端身份驗證。

TokenIssuedSuccessEvent & TokenIssuedFailureEvent

獲取用於請求標識符、訪問標記、刷新標記和受權代碼的成功/失敗嘗試。

TokenIntrospectionSuccessEvent & TokenIntrospectionFailureEvent

獲取成功的令牌內省請求。

TokenRevokedSuccessEvent

獲取成功的令牌撤銷請求。

UserLoginSuccessEvent & UserLoginFailureEvent

由quickstart UI引起,用於成功/失敗的用戶登陸。

UserLogoutSuccessEvent

獲取成功的註銷請求。

ConsentGrantedEvent & ConsentDeniedEvent

在贊成UI中引起。

UnhandledExceptionEvent

獲取未處理的異常。

十6、Cryptography, Keys and HTTPS

IdentityServer依賴於幾個加密機制來完成其工做。 

令牌簽名和驗證

IdentityServer須要非對稱密鑰對來簽署和驗證JWT。 該密鑰對能夠是證書/私鑰組合或原始RSA密鑰。 不管如何,它必須支持帶有SHA256的RSA。

加載簽名密鑰和相應的驗證部分由ISigningCredentialStore和IValidationKeysStore的實現完成。 若是您想自定義加載密鑰,您能夠實現這些接口並使用DI註冊它們。

DI構建器擴展有幾種方便的方法來設置簽名和驗證密鑰 - 請參閱此處

Signing key rollover

雖然一次只能使用一個簽名鍵,可是能夠爲發現文檔發佈多個驗證鍵。這對於鍵翻轉頗有用。

rollover一般以下所示:

  1. 您請求/建立新的key material
  2. 除了當前的驗證密鑰以外,還要發佈新的驗證密鑰。 您可使用AddValidationKeys構建器擴展方法。
  3. 全部客戶機和api如今都有機會在下次更新發現文檔的本地副本時瞭解新的密鑰
  4. 在必定時間(例如24小時)以後,全部客戶端和API如今應該接受舊密鑰材料和新密鑰材料
  5. 只要你願意,就能夠保留舊的密鑰材料,也許你有須要驗證的長壽命令牌
  6. 當舊密鑰材料再也不使用時,將其退役
  7. 全部客戶端和API將在下次更新發現文檔的本地副本時「忘記」舊密鑰

這要求客戶端和API使用發現文檔,而且還具備按期刷新其配置的功能。

數據保護

ASP.NET Core中的Cookie身份驗證(或MVC中的防僞)使用ASP.NET Core數據保護功能。 根據您的部署方案,這可能須要額外的配置。 有關更多信息,請參閱Microsoft文檔

HTTPS

咱們不強制使用HTTPS,但對於生產來講,它與IdentityServer的每次交互都是強制性的。

 

十7、Grant Types

授予類型是一種指定客戶端如何與IdentityServer交互的方式。 OpenID Connect和OAuth 2規範定義瞭如下受權類型: 

  • Implicit
  • Authorization code
  • Hybrid
  • Client credentials
  • Resource owner password
  • Refresh tokens
  • Extension grants

您能夠經過客戶端配置上的AllowedGrantTypes屬性指定客戶端可使用的受權類型。

客戶端能夠配置爲使用多種受權類型(例如,用於以用戶爲中心的操做的混合以及用於服務器到服務器通訊的客戶端憑證)。 GrantTypes類可用於從典型的授予類型組合中進行選擇:

Client.AllowedGrantTypes = GrantTypes.HybridAndClientCredentials;

您也能夠手動指定受權類型列表:

Client.AllowedGrantTypes =
{
    GrantType.Hybrid,
    GrantType.ClientCredentials,
    "my_custom_grant_type"
};

若是您想經過瀏覽器通道傳輸訪問令牌,則還須要明確地在客戶端配置上容許使用該令牌:

Client.AllowAccessTokensViaBrowser = true;

其他部分,簡要介紹受權類型,以及什麼時候使用它們。 還建議您另外閱讀相應的規格以更好地理解差別。

Client credentials

這是最簡單的受權類型,用於服務器到服務器通訊 - 始終表明客戶端而不是用戶請求令牌。

使用此受權類型,您能夠向令牌端點發送令牌請求,並獲取表明客戶端的訪問令牌。 客戶端一般必須使用其客戶端ID和密鑰對令牌端點進行身份驗證。


Resource owner password

資源全部者密碼授予類型容許經過將用戶名和密碼發送給令牌端點來表明用戶請求令牌。 這就是所謂的「非交互式」認證,一般不推薦。

一般對於信任應用使用此受權模式,但通常建議是使用implicit或hybrid 流程來替代用戶身份驗證。

查看資源全部者密碼快速入門以獲取如何使用它的示例。 您還須要提供用於實現IResourceOwnerPasswordValidator接口的用戶名/密碼驗證代碼。 你能夠在這裏找到更多關於這個接口的信息。


Implicit

 隱式受權類型針對基於瀏覽器的應用程序進行了優化。 用於僅用戶身份驗證(服務器端和JavaScript應用程序)或身份驗證和訪問令牌請求(JavaScript應用程序)。

在隱式流程中,全部令牌都經過瀏覽器傳輸,所以不容許刷新令牌等高級功能。

本快速入門顯示了服務端Web應用程序的身份驗證,並顯示了JavaScript。


Authorization code

受權代碼流最初由OAuth 2指定,並提供了一種在反向通道上檢索令牌而不是瀏覽器前端通道的方法。 它也支持客戶端認證。

雖然這種受權類型自己是受支持的,但一般建議您將其與身份令牌結合使用,將其轉換爲所謂的混合流。 混合流程爲您提供重要的額外功能,如簽名的協議響應


Hybrid

混合流是隱式和受權代碼流的組合 - 它使用多個授予類型的組合,最典型的是code id_token。

在混合流中,身份令牌經過瀏覽器通道傳輸,幷包含簽名的協議響應以及受權代碼等其餘部件的簽名。這能夠緩解適用於瀏覽器端的大量攻擊。成功驗證響應後,使用back-channel來檢索訪問和刷新令牌。

對於想要檢索訪問令牌(也多是刷新令牌)的本地應用程序,這是推薦的流程,用於服務器端Web應用程序和本地桌面/移動應用程序。

查看此快速入門以獲取有關在MVC中使用混合流的更多信息


Refresh tokens

刷新令牌容許得到API的長期訪問權限。

刷新令牌容許請求新的訪問令牌,而無需用戶交互。 每次客戶端刷新令牌時,都須要對IdentityServer進行(認證)後向通道調用。 這容許檢查刷新標記是否仍然有效,或者在此期間已被撤銷。

在混合、受權代碼和資源全部者密碼流中支持刷新令牌。要請求刷新令牌,客戶端須要在令牌請求中包含offline_access範圍(而且必須被受權請求該範圍)。


Extension grants

擴展授予容許使用新的授予類型擴展令牌端點。有關更多細節,請參見本文


Incompatible grant types

禁止一些受權類型組合:

  • 混合隱式和受權代碼或混合將容許從更安全的基於代碼的流降級攻擊到隱式攻擊。
  • 容許受權碼和混合模式二者一樣使人擔心

 

十8、Secrets

secret解析和驗證是身份服務器中的可擴展點,開箱即用它支持共享secret以及經過基自己份驗證頭或POST主體傳輸共享secret。

建立一個共享的secret

如下代碼設置了散列共享密鑰:

var secret = new Secret("secret".Sha256());

這個密鑰如今能夠分配給客戶端或ApiResource。 請注意,二者不只支持單個祕密,並且還支持多個密鑰。 這對密鑰翻轉和旋轉頗有用:

var client = new Client
{
    ClientId = "client",
    ClientSecrets = new List<Secret> { secret },

    AllowedGrantTypes = GrantTypes.ClientCredentials,
    AllowedScopes = new List<string>
    {
        "api1", "api2"
    }
};

實際上,您也能夠爲密鑰分配說明和到期日期。 描述將用於日誌記錄,以及執行密鑰生命週期的截止日期:

var secret = new Secret(
    "secret".Sha256(),
    "2016 secret",
    new DateTime(2016, 12, 31));

使用共享密鑰進行身份驗證

您能夠將客戶端ID /secret組合做爲POST正文的一部分發送:

POST /connect/token

client_id=client1&
client_secret=secret&
...

..或做爲basic身份驗證頭:

POST /connect/token

Authorization: Basic xxxxx

...

您可使用如下C#代碼手動建立basic身份驗證頭:

var credentials = string.Format("{0}:{1}", clientId, clientSecret);
var headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", headerValue);

IdentityModel庫具備名爲TokenClient和IntrospectionClient的輔助類,它們封裝了身份驗證和協議消息。

除了共享secret

還有其餘技術來驗證客戶端,例如 基於公鑰/私鑰加密。 IdentityServer包括對私鑰JWT客戶機密鑰的支持(請參閱RFC 7523)。

secret可擴展性一般包含三件事:

  • 一個secret的定義
  • 一個知道如何從傳入請求中提取secret的secret解析器
  • 一個secret驗證器,知道如何根據定義驗證解析的secret

secret解析器和驗證器是ISecretParser和ISecretValidator接口的實現。 要使它們可用於IdentityServer,您須要將它們註冊到DI容器,例如:

builder.AddSecretParser<ClientAssertionSecretParser>()
builder.AddSecretValidator<PrivateKeyJwtSecretValidator>()

咱們的默認私鑰JWTsecret驗證器指望完整的(leaf)證書做爲secret定義上的base64。而後,該證書將用於驗證自簽名JWT上的簽名,例如:

var client = new Client
{
    ClientId = "client.jwt",
    ClientSecrets =
    {
        new Secret
        {
            Type = IdentityServerConstants.SecretTypes.X509CertificateBase64,
            Value = "MIIDATCCAe2gAwIBAgIQoHUYAquk9rBJcq8W+F0FAzAJBgUrDgMCHQUAMBIxEDAOBgNVBAMTB0RldlJvb3QwHhcNMTAwMTIwMjMwMDAwWhcNMjAwMTIwMjMwMDAwWjARMQ8wDQYDVQQDEwZDbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSaY4x1eXqjHF1iXQcF3pbFrIbmNw19w/IdOQxbavmuPbhY7jX0IORu/GQiHjmhqWt8F4G7KGLhXLC1j7rXdDmxXRyVJBZBTEaSYukuX7zGeUXscdpgODLQVay/0hUGz54aDZPAhtBHaYbog+yH10sCXgV1Mxtzx3dGelA6pPwiAmXwFxjJ1HGsS/hdbt+vgXhdlzud3ZSfyI/TJAnFeKxsmbJUyqMfoBl1zFKG4MOvgHhBjekp+r8gYNGknMYu9JDFr1ue0wylaw9UwG8ZXAkYmYbn2wN/CpJl3gJgX42/9g87uLvtVAmz5L+rZQTlS1ibv54ScR2lcRpGQiQav/LAgMBAAGjXDBaMBMGA1UdJQQMMAoGCCsGAQUFBwMCMEMGA1UdAQQ8MDqAENIWANpX5DZ3bX3WvoDfy0GhFDASMRAwDgYDVQQDEwdEZXZSb290ghAsWTt7E82DjU1E1p427Qj2MAkGBSsOAwIdBQADggEBADLje0qbqGVPaZHINLn+WSM2czZk0b5NG80btp7arjgDYoWBIe2TSOkkApTRhLPfmZTsaiI3Ro/64q+Dk3z3Kt7w+grHqu5nYhsn7xQFAQUf3y2KcJnRdIEk0jrLM4vgIzYdXsoC6YO+9QnlkNqcN36Y8IpSVSTda6gRKvGXiAhu42e2Qey/WNMFOL+YzMXGt/nDHL/qRKsuXBOarIb++43DV3YnxGTx22llhOnPpuZ9/gnNY7KLjODaiEciKhaKqt/b57mTEz4jTF4kIg6BP03MUfDXeVlM1Qf1jB43G2QQ19n5lUiqTpmQkcfLfyci2uBZ8BkOhXr3Vk9HIk/xBXQ="
        }
    },

    AllowedGrantTypes = GrantTypes.ClientCredentials,
    AllowedScopes = { "api1", "api2" }
};

您能夠實現本身的secret驗證器(或擴展咱們的secret驗證器)來實現例如 相反,鏈信任驗證。

 

十9、Extension Grants

OAuth 2.0定義了令牌端點的標準受權類型,例如password,authorization_code和refresh_token。 擴展受權是一種添加對非標準令牌頒發方案(如令牌轉換,委派或自定義憑據)的支持的方法。

您能夠經過實現IExtensionGrantValidator接口來添加對其餘受權類型的支持:

public interface IExtensionGrantValidator
{
    /// <summary>
    /// Handles the custom grant request.
    /// </summary>
    /// <param name="request">The validation context.</param>
    Task ValidateAsync(ExtensionGrantValidationContext context);

    /// <summary>
    /// Returns the grant type this validator can deal with
    /// </summary>
    /// <value>
    /// The type of the grant.
    /// </value>
    string GrantType { get; }
}

他的ExtensionGrantValidationContext對象使您能夠訪問:

  • 傳入令牌請求 - 衆所周知的驗證值,以及任何自定義值(經過Raw集合)
  • 結果 - 錯誤或成功
  • 自定義響應參數

要註冊擴展受權,請將其添加到DI:

builder.AddExtensionGrantValidator<MyExtensionsGrantValidator>();

示例:使用擴展受權進行簡單委派

想象一下如下場景 - 前端客戶端使用經過交互流(例如混合流)獲取的令牌來調用中間層API。 此中間層API(API 1)如今但願表明交互式用戶調用後端API(API 2):

換句話說,中間層API(API 1)須要包含用戶身份的訪問令牌,但須要具備後端API(API 2)的scope。

實施擴展受權 

前端會將令牌發送到API 1,如今須要在IdentityServer上使用API 2的新令牌交換此令牌。

在線上,對交換的令牌服務的調用可能以下所示:

POST /connect/token

grant_type=delegation&
scope=api2&
token=...&
client_id=api1.client
client_secret=secret

擴展受權驗證程序的工做是經過驗證傳入令牌並返回表示新令牌的結果來處理該請求:

public class DelegationGrantValidator : IExtensionGrantValidator
{
    private readonly ITokenValidator _validator;

    public DelegationGrantValidator(ITokenValidator validator)
    {
        _validator = validator;
    }

    public string GrantType => "delegation";

    public async Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        var userToken = context.Request.Raw.Get("token");

        if (string.IsNullOrEmpty(userToken))
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return;
        }

        var result = await _validator.ValidateAccessTokenAsync(userToken);
        if (result.IsError)
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return;
        }

        // get user's identity
        var sub = result.Claims.FirstOrDefault(c => c.Type == "sub").Value;

        context.Result = new GrantValidationResult(sub, GrantType);
        return;
    }
}

不要忘記在DI上註冊驗證器。

註冊委託客戶端

您須要在IdentityServer中進行客戶端註冊,以容許客戶端使用此新的擴展受權,例如:

var client = new client
{
    ClientId = "api1.client",
    ClientSecrets = new List<Secret>
    {
        new Secret("secret".Sha256())
    },

    AllowedGrantTypes = { "delegation" },

    AllowedScopes = new List<string>
    {
        "api2"
    }
}

調用令牌端點

在API 1中,您如今能夠本身構建HTTP有效內容,或使用IdentityModel幫助程序庫:

public async Task<TokenResponse> DelegateAsync(string userToken)
{
    var payload = new
    {
        token = userToken
    };

    // create token client
    var client = new TokenClient(disco.TokenEndpoint, "api1.client", "secret");

    // send custom grant to token endpoint, return response
    return await client.RequestCustomGrantAsync("delegation", "api2", payload);
}

TokenResponse.AccessToken如今將包含委託訪問令牌。

 

二10、Resource Owner Password Validation

若是要使用OAuth 2.0資源全部者密碼憑據受權(也稱爲密碼),則須要實現並註冊IResourceOwnerPasswordValidator接口: 

public interface IResourceOwnerPasswordValidator
{
    /// <summary>
    /// Validates the resource owner password credential
    /// </summary>
    /// <param name="context">The context.</param>
    Task ValidateAsync(ResourceOwnerPasswordValidationContext context);
}

在上下文中,您將找到已解析的協議參數,如UserName和Password,若是您想查看其餘輸入數據,還能夠找到原始請求。

而後,您的工做是實施密碼驗證並相應地在上下文中設置結果。 請參閱GrantValidationResult文檔。

 

二11、Refresh Tokens

因爲訪問令牌的生命週期有限,所以刷新令牌容許在沒有用戶交互的狀況下請求新的訪問令牌。 

如下流程支持刷新令牌:authorization code, hybrid 和resource owner password憑據流。 須要明確受權客戶端經過將AllowOfflineAccess設置爲true來請求刷新令牌。

其餘客戶端設置

AbsoluteRefreshTokenLifetime

刷新令牌的最長生命週期,以秒爲單位。 默認爲2592000秒/ 30天。 Zero與RefreshTokenExpiration = Sliding一塊兒使用時永不過時的刷新令牌

SlidingRefreshTokenLifetime

刷新令牌的生命週期以秒爲單位。 默認爲1296000秒/ 15天

RefreshTokenUsage

ReUse 刷新令牌時刷新令牌句柄將保持不變

OneTime 刷新令牌時將更新刷新令牌句柄

RefreshTokenExpiration

Absolute刷新令牌將在固定時間點到期(由AbsoluteRefreshTokenLifetime指定)

Sliding 刷新令牌時,將刷新刷新令牌的生命週期(按SlidingRefreshTokenLifetime中指定的數量)。 生命週期不會超過AbsoluteRefreshTokenLifetime。

UpdateAccessTokenClaimsOnRefresh

獲取或設置一個值,該值指示是否應在刷新令牌請求上更新訪問令牌(及其聲明)。

 

二12、Reference Tokens

訪問令牌能夠有兩種形式 - 自包含或引用。 

JWT令牌將是一個自包含的訪問令牌 - 它是一個帶有聲明和過時的受保護數據結構。 一旦API瞭解了密鑰材料,它就能夠驗證自包含的令牌,而無需與發行者進行通訊。 這使得JWT難以撤銷。 它們將一直有效,直到它們過時。

使用引用令牌時 - IdentityServer會將令牌的內容存儲在數據存儲中,而且只會將此令牌的惟一標識符發回給客戶端。 接收此引用的API必須打開與IdentityServer的反向通道通訊以驗證令牌。

您可使用如下設置切換客戶端的令牌類型:

client.AccessTokenType = AccessTokenType.Reference;

IdentityServer提供了OAuth 2.0 introspection 規範的實現,該規範容許API取消引用令牌。 您可使用咱們的專用introspection 中間件或使用身份服務器身份驗證中間件,它能夠驗證JWT和引用令牌。

introspection 端點須要身份驗證 - 由於introspection 端點的客戶端是API,您能夠在ApiResource上配置密碼:

var api = new ApiResource("api1")
{
    ApiSecrets = { new Secret("secret".Sha256()) }
}

 

二十3、CORS

IdentityServer中的許多端點將經過基於JavaScript的客戶端的Ajax調用進行訪問。 鑑於IdentityServer最有可能託管在與這些客戶端不一樣的源上,這意味着須要配置跨源資源共享(CORS)。 

基於客戶端的CORS配置

配置CORS的一種方法是在客戶端配置上使用AllowedCorsOrigins集合。 只需將客戶端的原點添加到集合中,IdentityServer中的默認配置將查詢這些值以容許來自源的跨源調用。

配置CORS時,請務必使用origin(不是URL)。 例如:https://foo:123/是一個URL,而https://foo:123是一個origin。

若是您使用咱們提供的「in-memory」或基於EF的客戶端配置,則將使用此默認CORS實現。 若是您定義本身的IClientStore,那麼您將須要實現本身的自定義CORS策略服務(參見下文)。

自定義Cors策略服務

IdentityServer容許託管應用程序實現ICorsPolicyService以徹底控制CORS策略。

要實現的惟一方法是:Task<bool> IsOriginAllowedAsync(string origin)。 若是容許origin則返回true,不然返回false。

實現後,只需在DI中註冊實現,而後IdentityServer將使用您的自定義實現。

DefaultCorsPolicyService

若是您只是但願對一組容許的origin進行硬編碼,那麼可使用一個名爲DefaultCorsPolicyService的預構建的ICorsPolicyService實現。 這將在DI中配置爲單例,並使用其AllowedOrigins集合進行硬編碼,或將AllowAll標誌設置爲true以容許全部來源。 例如,在ConfigureServices中:

var cors = new DefaultCorsPolicyService(_loggerFactory.CreateLogger<DefaultCorsPolicyService>())
{
    AllowedOrigins = { "https://foo", "https://bar" }
};
services.AddSingleton<ICorsPolicyService>(cors);

請謹慎使用AllowAll。

將IdentityServer的CORS策略與ASP.NET Core的CORS策略混合使用

dentityServer使用ASP.NET Core的CORS中間件來提供其CORS實現。 託管IdentityServer的應用程序可能還須要CORS用於本身的自定義端點。 一般,二者應該在同一個應用程序中一塊兒工做。

您的代碼應使用ASP.NET Core中記錄的CORS功能,而不考慮IdentityServer。 這意味着您應該定義策略並正常註冊中間件。 若是您的應用程序在ConfigureServices中定義策略,那麼這些策略應該繼續在您使用它們的相同位置(在您配置CORS中間件的位置或在控制器代碼中使用MVC EnableCors屬性的位置)。 相反,若是您使用CORS中間件(經過策略構建器回調)定義內聯策略,那麼它也應該繼續正常工做。

若是您決定建立自定義ICorsPolicyProvider,那麼在您使用ASP.NET Core CORS服務和IdentityServer之間可能存在衝突的一種狀況。 鑑於ASP.NET Core的CORS服務和中間件的設計,IdentityServer實現了本身的自定義ICorsPolicyProvider並將其註冊到DI系統中。 幸運的是,IdentityServer實現旨在使用裝飾器模式來包裝已在DI中註冊的任何現有ICorsPolicyProvider。 這意味着你也能夠實現ICorsPolicyProvider,但它只須要在DI中的IdentityServer以前註冊(例如在ConfigureServices中)。

 

二十4、Discovery

能夠在https://baseaddress/.well-known/openid-configuration找到發現文檔。 它包含有關IdentityServer的端點,密鑰材料和功能的信息。 

默認狀況下,全部信息都包含在發現文檔中,但經過使用配置選項,您能夠隱藏各個部分,例如:

services.AddIdentityServer(options =>
{
    options.Discovery.ShowIdentityScopes = false;
    options.Discovery.ShowApiScopes = false;
    options.Discovery.ShowClaims = false;
    options.Discovery.ShowExtensionGrantTypes = false;
});

擴展發現

您能夠向發現文檔添加自定義條目,例如:

services.AddIdentityServer(options =>
{
    options.Discovery.CustomEntries.Add("my_setting", "foo");
    options.Discovery.CustomEntries.Add("my_complex_setting",
        new
        {
            foo = "foo",
            bar = "bar"
        });
});

當您添加以〜開頭的自定義值時,它將擴展爲IdentityServer基址如下的絕對路徑,例如:

options.Discovery.CustomEntries.Add("my_custom_endpoint", "~/custom");

若是要徹底控制發現(和jwks)文檔的呈現,能夠實現IDiscoveryResponseGenerator接口(或從咱們的默認實現派生)。

 

二十5、Adding more API Endpoints

您能夠向託管IdentityServer4的應用程序添加更多API端點。

您一般但願經過它們所託管的IdentityServer實例來保護這些API。這不是問題。 只需將令牌驗證處理程序添加到主機(請參閱此處):

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    // details omitted
    services.AddIdentityServer();

    services.AddAuthentication()
        .AddIdentityServerAuthentication("token", isAuth =>
        {
            isAuth.Authority = "base_address_of_identityserver";
            isAuth.ApiName = "name_of_api";
        });
}

在您的API上,您須要添加[Authorize]屬性並顯式引用您要使用的身份驗證方案(在此示例中這是令牌,但您能夠選擇您喜歡的任何名稱):

public class TestController : ControllerBase
{
    [Route("test")]
    [Authorize(AuthenticationSchemes = "token")]
    public IActionResult Get()
    {
        var claims = User.Claims.Select(c => new { c.Type, c.Value }).ToArray();
        return Ok(new { message = "Hello API", claims });
    }
}

若是要從瀏覽器調用該API,則還須要配置CORS。

發現

若是須要,您還能夠將端點添加到發現文檔中,例如:

services.AddIdentityServer(options =>
{
    options.Discovery.CustomEntries.Add("custom_endpoint", "~/api/custom");
})

 

二十6、Adding new Protocols

除了對OpenID Connect和OAuth 2.0的內置支持以外,IdentityServer4還容許添加對其餘協議的支持。 

您能夠將這些附加協議端點添加爲中間件或使用例如 MVC控制器。 在這兩種狀況下,您均可以訪問ASP.NET Core DI系統,該系統容許重用咱們的內部服務,例如訪問客戶端定義或密鑰材料。

能夠在此處找到添加WS-Federation支持的示例

典型認證工做流程

身份驗證請求一般以下所示:

  • 身份驗證請求到達協議端點
  • 協議端點執行輸入驗證
  • 重定向到登陸頁面,返回URL設置回協議端點(若是用戶是匿名的)
    • 經過IIdentityServerInteractionService訪問當前請求詳細信息
    • 用戶身份驗證(本地或經過外部身份驗證中間件)
    • 登陸用戶
    • 重定向回協議端點
  • 建立協議響應(令牌建立和重定向回客戶端)

Useful IdentityServer服務

要實現上述工做流程,須要與IdentityServer創建一些交互點。

訪問配置並重定向到登陸頁面

您能夠經過將IdentityServerOptions類注入代碼來訪問IdentityServer配置。 這個,例如 具備登陸頁面的已配置路徑:

var returnUrl = Url.Action("Index");
returnUrl = returnUrl.AddQueryString(Request.QueryString.Value);

var loginUrl = _options.UserInteraction.LoginUrl;
var url = loginUrl.AddQueryString(_options.UserInteraction.LoginReturnUrlParameter, returnUrl);

return Redirect(url);

登陸頁面與當前協議請求之間的交互

IIdentityServerInteractionService支持將協議返回URL轉換爲已解析和驗證的上下文對象:

var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

默認狀況下,交互服務僅瞭解OpenID Connect協議消息。 要擴展支持,您能夠編寫本身的IReturnUrlParser:

public interface IReturnUrlParser
{
    bool IsValidReturnUrl(string returnUrl);
    Task<AuthorizationRequest> ParseAsync(string returnUrl);
}

..而後在DI中註冊解析器:

builder.Services.AddTransient<IReturnUrlParser, WsFederationReturnUrlParser>();

這容許登陸頁面獲取客戶端配置和其餘協議參數等信息。

訪問用於建立協議響應的配置和密鑰材料

經過將IKeyMaterialService注入代碼,您能夠訪問配置的簽名憑據和驗證密鑰:

var credential = await _keys.GetSigningCredentialsAsync();
var key = credential.Key as Microsoft.IdentityModel.Tokens.X509SecurityKey;

var descriptor = new SecurityTokenDescriptor
{
    AppliesToAddress = result.Client.ClientId,
    Lifetime = new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddSeconds(result.Client.IdentityTokenLifetime)),
    ReplyToAddress = result.Client.RedirectUris.First(),
    SigningCredentials = new X509SigningCredentials(key.Certificate, result.RelyingParty.SignatureAlgorithm, result.RelyingParty.DigestAlgorithm),
    Subject = outgoingSubject,
    TokenIssuerName = _contextAccessor.HttpContext.GetIdentityServerIssuerUri(),
    TokenType = result.RelyingParty.TokenType
};

 

二十7、Tools

IdentityServerTools類是在爲IdentityServer編寫可擴展性代碼時可能須要的有用內部工具的集合。 要使用它,請將其注入您的代碼,例如 控制器: 

public MyController(IdentityServerTools tools)
{
    _tools = tools;
}

IssueJwtAsync方法容許使用IdentityServer令牌建立引擎建立JWT令牌。 IssueClientJwtAsync是用於爲服務器到服務器通訊建立令牌的簡單版本(例如,當您必須從代碼中調用受IdentityServer保護的API時):

public async Task<IActionResult> MyAction()
{
    var token = await _tools.IssueClientJwtAsync(
        clientId: "client_id",
        lifetime: 3600,
        audiences: new[] { "backend.api" });

    // more code
}
相關文章
相關標籤/搜索