IdentityServer4-快速入門

1、設置和概述html

2、使用客戶端憑證保護APInode

3、使用密碼保護APIgit

4、使用OpenID Connect添加用戶驗證github

5、添加對外部認證的支持算法

6、切換到Hybrid Flow並添加API訪問權限sql

7、Using ASP.NET Core Identity數據庫

8、添加一個JavaScript客戶端json

9、使用EntityFramework core進行配置和操做數據後端

10、社區快速入門&樣品api

 

1、設置和概述

1,使用 dotnet new mvc 建立一個mvc項目

2,nuget IdentityServer4 

3,修改Startup

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddIdentityServer()//在DI中註冊IdentityServer服務,它還爲運行時狀態註冊一個內存存儲
            .AddDeveloperSigningCredential();//設置臨時簽名憑證
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();
    }
}

 

2、使用客戶端憑證保護API

在這個場景中,咱們將定義一個API和一個但願訪問它的客戶端。客戶端將在IdentityServer中請求訪問令牌,並使用它得到對API的訪問。 

定義API

建立一個Config,cs文件,在該文件中定義您但願保護的系統中的資源,例如api。

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        new ApiResource("api1", "My API")
    };
}

定義Client

定義訪問這個api的client

對於此場景,客戶端將沒有交互式用戶,並將使用所謂的client secret與IdentityServer進行身份驗證。將如下代碼添加到配置中。cs文件:

        public static IEnumerable<Client> GetClient()
        {
            return new List<Client>()
            {
                new Client(){
                    ClientId="client",
                    //沒有交互式用戶,使用clientid/secret進行身份驗證
                    AllowedGrantTypes=GrantTypes.ClientCredentials,
                    //secret認證
                    ClientSecrets={new Secret("secret".Sha256())},
                    //客戶端有權訪問的範圍
                    AllowedScopes={"api"}
                }
            };
        }

配置IdentityServer

在ConfigureServices添加AddInMemoryApiResources與AddInMemoryClients方法

public void ConfigureServices(IServiceCollection services)
{
    // configure identity server with in-memory stores, keys, clients and resources
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients());
}

打開 http://localhost:5000/.well-known/openid-configuration 你應該看看所謂的發現文件。您的客戶端和api將使用它來下載必要的配置數據。

添加一個API項目

添加一個api項目,將url設置爲 http://localhost:5001 

1,添加controller

[Route("identity")]
[Authorize]
public class IdentityController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
    }
}

2,配置

最後一步是將身份驗證服務添加到DI,將身份驗證中間件添加到管道。這些將會:

  • 驗證傳入的令牌以確保它來自受信任的頒發者
  • 驗證該令牌是否適用於此api(又名scope)

nuget IdentityServer4.AccessTokenValidation 

更新Startup以下

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvcCore()
            .AddAuthorization()
            .AddJsonFormatters();
        //AddAuthentication將認證服務添加到DI,並將「Bearer」配置爲默認方案。
        services.AddAuthentication("Bearer")
            //將IdentityServer訪問令牌驗證處理程序添加到DI中以供驗證服務使用
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

                options.ApiName = "api1";
            });
    }

    public void Configure(IApplicationBuilder app)
    {
        //UseAuthentication將認證中間件添加到管道,所以每次調用主機時都會自動執行認證。
        app.UseAuthentication();

        app.UseMvc();
    }
}

若是使用瀏覽器導航到控制器(http://localhost:5001/identity),則應該獲得401狀態碼做爲回報。這意味着您的API須要憑據。
就是這樣,API如今由IdentityServer保護。

建立client

添加一個console項目

IdentityServer中的令牌端點實現OAuth 2.0協議,您可使用原始HTTP訪問它。可是,咱們有一個名爲IdentityModel的客戶端庫,它將協議交互封裝在一個易於使用的API中。

nuget IdentityModel 

IdentityModel包含一個用於發現端點的客戶端庫。 這樣您只須要知道IdentityServer的基地址 - 能夠從元數據中讀取實際的端點地址:

// 從元數據發現端點
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

接下來,您可使用TokenClient類來請求令牌。 要建立實例,您須要傳入令牌端點地址,client ID和secret。

接下來,您可使用requestcredenticlientalsasync方法爲您的API請求一個令牌:

// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);//將access token賦值到https://jwt.io/能夠查看詳細信息

最後一步是調用API。
要將訪問令牌發送到API,一般使用HTTP受權頭。這是使用SetBearerToken擴展方法完成的:

// call api
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);

var response = await client.GetAsync("http://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var content = await response.Content.ReadAsStringAsync();
    Console.WriteLine(JArray.Parse(content));
}

 案例下載:https://pan.baidu.com/s/1xYxymmnn6giMUphnnCGaaQ

 

3、使用密碼保護API

客戶端輸入用戶名和密碼獲取訪問令牌,經過訪問令牌訪問資源,該規範建議僅將「資源全部者密碼授予」用於「可信」應用程序

添加用戶

TestUser類表示測試用戶。 讓咱們經過將如下代碼添加到咱們的配置類來建立幾個用戶:

首先將如下using語句添加到Config.cs文件中:

using IdentityServer4.Test;

public static List<TestUser> GetUsers()
{
    return new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "1",
            Username = "alice",
            Password = "password"
        },
        new TestUser
        {
            SubjectId = "2",
            Username = "bob",
            Password = "password"
        }
    };
}

而後向IdentityServer註冊測試用戶:

public void ConfigureServices(IServiceCollection services)
{
    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

AddTestUsers擴展方法在底層作了幾件事情

  • 增長了對資源全部者密碼受權的支持
  • 增長了對登陸UI一般使用的用戶相關服務的支持
  • 基於測試用戶添加了對配置文件服務的支持

配置一個支持密碼受權的客戶端

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        // other clients omitted...

        // resource owner password grant client
        new Client
        {
            ClientId = "ro.client",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            AllowedScopes = { "api1" }
        }
    };
}

使用密碼授予請求令牌

客戶端看起來很是相似於咱們爲客戶端憑據受權所作的操做。 主要區別在於客戶端會以某種方式收集用戶的密碼,並在令牌請求期間將其發送給令牌服務。

// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

案例下載:https://pan.baidu.com/s/1q-UYw_34hX00MqxiZp524g

 

4、使用OpenID Connect添加用戶驗證

添加UI

OpenID Connect所需的全部協議支持都已內置到IdentityServer中。 您須要爲登陸,註銷,贊成和錯誤提供必要的UI部分。

雖然每一個IdentityServer實現的外觀和感受以及確切的工做流程可能老是不一樣,但咱們提供了一個基於MVC的示例UI,您能夠將其用做起點。

這個用戶界面能夠在Quickstart UI倉庫中找到。 您能夠克隆或下載此repo,並將控制器,視圖,模型和CSS放入您的IdentityServer Web應用程序。

建立一個MVC應用,而後將 Quickstart UI複製到項目中,nuget  IdentityServer4 。並配置Startup:

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

    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseIdentityServer();

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

建立一個MVC客戶端 

要將OpenID Connect身份驗證支持添加到MVC應用程序,請將如下內容添加到啓動時的ConfigureServices中: 

            //AddAuthentication將認證服務添加到DI
            services.AddAuthentication(options=>{
                options.DefaultScheme="Cookies";//設置Cookies爲主要認證手段
                options.DefaultChallengeScheme="oidc";//當須要登陸時使用OpenID Connect方案
            })
            .AddCookie("Cookies")//使用AddCookie添加能夠處理cookie的處理程序。
            .AddOpenIdConnect("oidc",options=>{
                options.SignInScheme="Cookies";
                options.Authority="http://localhost:5000";
                options.RequireHttpsMetadata=false;
                options.ClientId="client";
                options.SaveTokens=true;
            });

AddOpenIdConnect用於配置執行OpenID鏈接協議的處理程序。受權代表咱們信任身份服務器。而後咱們經過ClientId識別這個客戶端。一旦OpenID鏈接協議完成,SignInScheme將使用cookie處理程序發出cookie。

savetoken用於將標識符從IdentityServer中持久化到cookie中(稍後須要它們)。

此外,咱們關閉了JWT聲明類型映射,以容許衆所周知的聲明(例如'sub'和'idp')經過非混淆的聲明: 

 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();  

 而後爲了確保驗證服務在每一個請求上執行,請添加UseAuthentication以在啓動時進行配置:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseAuthentication();//認證中間件應該在管道中的MVC以前添加。

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

添加對OpenID Connect Identity Scopes的支持

與OAuth 2.0相似,OpenID Connect也使用了做用域概念。一樣,做用域表示您但願保護和客戶端但願訪問的內容。與OAuth相反,OIDC中的做用域並不表示api,而是用戶id、名稱或電子郵件地址等標識數據。

在Config.cs中建立一個IdentityResource對象集合,添加對標準openid(subject id)和profile(名字,姓氏等)做用域的支持

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

修改Startup

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

    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

爲OpenID Connect隱式流添加客戶端

最後一步是將MVC客戶端的新配置條目添加到IdentityServer。

基於OpenID Connect的客戶端與咱們迄今添加的OAuth 2.0客戶端很是類似。 但因爲OIDC中的流程始終是交互式的,所以咱們須要將一些重定向URL添加到咱們的配置中。

將如下內容添加到客戶端配置中:

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        // 其餘客戶被忽略...

        // OpenID Connect隱式流程客戶端(MVC)
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Implicit,

            // 登陸後重定向到哪裏
            RedirectUris = { "http://localhost:5001/signin-oidc" },

            // 註銷後重定向到哪裏
            PostLogoutRedirectUris = { "http://localhost:5001/signout-callback-oidc" },

            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile
            }
        }
    };
}

 測試客戶端

如今,最終全部的東西都應該適用於新的MVC客戶端。

經過導航到受保護的控制器操做來觸發身份驗證握手。 您應該看到重定向到IdentityServer的登陸頁面。

 案例下載:https://pan.baidu.com/s/1XHL4eRzp3oqIK3ubMF-NLQ

 

5、添加對外部認證的支持

接下來咱們將添加對外部認證的支持。 這很是簡單,由於您真正須要的只是一個兼容ASP.NET Core的身份驗證處理程序。 

ASP.NET Core自己也支持Google,Facebook,Twitter,Microsoft賬戶和OpenID Connect。 另外你能夠在這裏找到許多其餘認證提供者的實現。

添加Google支持

要可以使用谷歌進行身份驗證,首先須要向它們註冊。這是在開發人員控制檯完成的。建立一個新項目,啓用谷歌+ API,並經過將/signin-google路徑添加到基本地址(例如http://localhost:5000/signin- Google)來配置本地標識服務器的回調地址。

若是您正在端口5000上運行——您可使用下面代碼片斷中的客戶端id/secret,由於這是咱們預先註冊的。

首先添加Google身份驗證處理程序到DI。 這是經過將此片斷添加到啓動時的ConfigureServices中完成的:

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

    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());

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

            options.ClientId = "434483408261-55tc8n0cs4ff1fe21ea8df2o443v2iuc.apps.googleusercontent.com";
            options.ClientSecret = "3gcoTrEDPPJ0ukn_aYYT6PWo";
        });
}

默認狀況下,IdentityServer專門爲外部認證的結果配置cookie處理程序(使用基於常量IdentityServerConstants.ExternalCookieAuthenticationScheme的方案)。 Google處理程序的配置而後使用該cookie處理程序。 爲了更好地理解這是如何完成的,請參閱Quickstart文件夾下的AccountController類。

進一步實驗

您能夠添加一個額外的外部提供者。 咱們有一個雲託管的IdentityServer4演示版本,您可使用OpenID Connect進行集成。

將OpenId Connect處理程序添加到DI中:

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

        options.ClientId = "434483408261-55tc8n0cs4ff1fe21ea8df2o443v2iuc.apps.googleusercontent.com";
        options.ClientSecret = "3gcoTrEDPPJ0ukn_aYYT6PWo";
    })
    .AddOpenIdConnect("oidc", "OpenID Connect", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
        options.SignOutScheme = IdentityServerConstants.SignoutScheme;

        options.Authority = "https://demo.identityserver.io/";
        options.ClientId = "implicit";

        options.TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name",
            RoleClaimType = "role"
        };
    });

 

6、切換到Hybrid Flow並添加API訪問權限

在前面的快速啓動中,咱們研究了API訪問和用戶身份驗證。如今咱們要把這兩個部分結合起來。 

OpenID Connect & OAuth 2.0組合的美妙之處在於,您能夠經過一個協議和一個與令牌服務的交換來實現。

在前面的quickstart中,咱們使用了OpenID鏈接隱式流。在隱式流中,全部令牌都經過瀏覽器傳輸,這對於身份令牌來講是徹底沒問題的。如今咱們還想請求一個訪問令牌。

訪問令牌比身份令牌更加敏感,若是不須要,咱們不但願將它們暴露於「外部」世界。 OpenID Connect包含一個名爲「混合流」的流程,它可讓咱們一箭雙鵰,身份令牌經過瀏覽器通道傳輸,所以客戶能夠在作更多工做以前驗證它。 若是驗證成功,客戶端會打開令牌服務的後端通道來檢索訪問令牌。

修改client配置

沒有多少必要的修改。首先,咱們但願容許客戶端使用混合流,此外,咱們還但願客戶端容許執行服務器到服務器的API調用,這些調用不在用戶的上下文中(這與咱們的客戶端憑證quickstart很是類似)。使用AllowedGrantTypes屬性表示。

接下來,咱們須要添加一個客戶端secret。這將用於檢索後通道上的訪問令牌。

最後,咱們還爲客戶端提供了對offline_access範圍的訪問權限——這容許爲長期存在的API訪問請求刷新令牌:

new Client
{
    ClientId = "mvc",
    ClientName = "MVC Client",
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

    ClientSecrets =
    {
        new Secret("secret".Sha256())
    },

    RedirectUris           = { "http://localhost:5002/signin-oidc" },
    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1"
    },
    AllowOfflineAccess = true
};

修改MVC客戶端

MVC客戶端的修改也是最小的——ASP.NET核心的OpenID鏈接處理器對混合流有內置的支持,因此咱們只須要更改一些配置值。

咱們配置 ClientSecret 以匹配IdentityServer上的secret。添加 offline_access 和 api1 做用域,並將 ResponseType 設置爲 code id_token (這基本上意味着「使用混合流」)

.AddOpenIdConnect("oidc", options =>
{
    options.SignInScheme = "Cookies";

    options.Authority = "http://localhost:5000";
    options.RequireHttpsMetadata = false;

    options.ClientId = "mvc";
    options.ClientSecret = "secret";
    options.ResponseType = "code id_token";

    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;

    options.Scope.Add("api1");
    options.Scope.Add("offline_access");
});

當您運行MVC客戶端時,除了贊成屏幕如今要求您提供額外的API和 offline access scope外,沒有太大區別。

使用訪問令牌

OpenID鏈接中間件爲您自動保存令牌(標識、訪問和刷新)。這就是savetoken設置的做用。

技術上,令牌存儲在cookie的屬性部分。 訪問它們的最簡單方法是使用Microsoft.AspNetCore.Authentication命名空間中的擴展方法。

例如在您的聲明視圖上:

<dt>access token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("access_token")</dd>

<dt>refresh token</dt>
<dd>@await ViewContext.HttpContext.GetTokenAsync("refresh_token")</dd>

要使用訪問令牌訪問API,您只需檢索令牌並將其設置在您的HttpClient上:

public async Task<IActionResult> CallApiUsingUserAccessToken()
{
    var accessToken = await HttpContext.GetTokenAsync("access_token");

    var client = new HttpClient();
    client.SetBearerToken(accessToken);
    var content = await client.GetStringAsync("http://localhost:5001/identity");

    ViewBag.Json = JArray.Parse(content).ToString();
    return View("json");
}

 

7、Using ASP.NET Core Identity

IdentityServer旨在提供靈活性,其中的一部分容許您爲用戶及其數據使用任何數據庫(包括密碼)。 若是你從一個新的用戶數據庫開始,那麼ASP.NET Identity是你能夠選擇的一個選項。 本快速入門介紹瞭如何將Identity Identity與Identity Identity一塊兒使用。 

這個快速入門假設你已經完成了全部的快速入門。 快速入門使用ASP.NET Identity的方法是從Visual Studio中的ASP.NET Identity模板建立一個新項目。 這個新項目將取代以前在快速入門中從頭開始構建的IdentityServer項目。 此解決方案中的全部其餘項目(針對客戶端和API)將保持不變。

新建ASP.NET Identity項目 

第一步是爲您的解決方案添加一個ASP.NET Identity的新項目。 鑑於ASP.NET身份須要大量代碼,所以使用Visual Studio中的模板是有意義的。 您最終將刪除IdentityServer的舊項目(假設您正在關注其餘快速入門),但您須要遷移幾個項目(或按照以前的快速入門中所述從頭開始重寫)。

nuget  dotnet new mvc --auth Individual 

修改hosting

不要忘記修改主機(如此處所述)以在端口5000上運行。這很是重要,所以現有客戶端和API項目將繼續運行。

添加IdentityServer包 

添加IdentityServer4.AspNetIdentity NuGet包。 這取決於IdentityServer4包,所以會自動添加爲傳遞依賴項。

Scopes和Clients配置

儘管這是IdentityServer的一個新項目,但咱們仍須要與以前的快速入門相同的範圍和客戶端配置。 將用於以前快速入門的配置類(在Config.cs中)複製到此新項目中。

new Client
{
    ClientId = "mvc",
    ClientName = "MVC Client",
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

    RequireConsent = false,

    ClientSecrets =
    {
        new Secret("secret".Sha256())
    },

    RedirectUris           = { "http://localhost:5002/signin-oidc" },
    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1"
    },
    AllowOfflineAccess = true
}

配置IdentityServer

與前面同樣,須要在Configure reservices中和Startup.cs中配置IdentityServer。

ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    // Add application services.
    services.AddTransient<IEmailSender, EmailSender>();

    services.AddMvc();

    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryPersistedGrants()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddAspNetIdentity<ApplicationUser>();
}

Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    // app.UseAuthentication(); // not needed, since UseIdentityServer adds the authentication middleware
    app.UseIdentityServer();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

建立用戶數據庫

鑑於這是一個新的ASP.NET Identity項目,您將須要建立數據庫。 您能夠經過從項目目錄運行命令提示符並運行 dotnet ef database update -c ApplicationDbContext 來執行此操做

案例下載:https://pan.baidu.com/s/1ZxVHNYApxyZMGcDg-XlTkg 

8、添加一個JavaScript客戶端

這個快速入門將展現如何構建JavaScript客戶端應用程序。 用戶將登陸到IdentityServer,使用IdentityServer發出的訪問令牌調用Web API,並註銷IdentityServer。

添加一個JavaScript的客戶端項目

添加一個空項目 

添加靜態文件中間件

鑑於此項目主要用於運行客戶端,咱們須要ASP.NET Core來提供構成咱們應用程序的靜態HTML和JavaScript文件。 靜態文件中間件旨在執行此操做。

在Configure方法中的Startup.cs中註冊靜態文件中間件:

public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();
    app.UseStaticFiles();
}

這個中間件如今將從應用程序的〜/ wwwroot文件夾中提供靜態文件。 這是咱們將放置HTML和JavaScript文件的地方。

引用oidc-client

在MVC項目中,咱們使用一個庫來處理OpenID Connect協議。 在這個項目中,咱們須要一個相似的庫,除了一個在JavaScript中工做而且被設計爲在瀏覽器中運行的庫。 oidc-client庫就是這樣一個庫。 它能夠經過NPM,Bower,以及從github直接下載。

NPM

若是您想使用NPM下載oidc-client,請按照如下步驟操做:

將一個新的NPM包文件添加到您的項目中,並將其命名爲package.json。

在package.json中添加一個依賴到oidc-client:

"dependencies": {
  "oidc-client": "1.4.1"
}

一旦保存了該文件,Visual Studio應該自動將這些軟件包恢復到名爲node_modules的文件夾中。

在〜/node_modules/oidc-client/dist文件夾中找到名爲oidc-client.js的文件,並將其複製到應用程序的〜/wwwroot文件夾中。 有更復雜的方法將您的NPM軟件包複製到〜/wwwroot中,但這些技術不在本快速入門的範圍以內。

添加您的HTML和JavaScript文件

在〜/wwwroot中,添加一個名爲index.html和callback.html的HTML文件,並添加一個名爲app.js的JavaScript文件。

index.html

這將是咱們應用程序的主頁面。 它將包含用於登陸,註銷並調用Web API的按鈕的HTML。 它還將包含<script>標籤以包含咱們的兩個JavaScript文件。 它還將包含用於向用戶顯示消息的<pre>。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <button id="login">Login</button>
    <button id="api">Call API</button>
    <button id="logout">Logout</button>

    <pre id="results"></pre>

    <script src="oidc-client.js"></script>
    <script src="app.js"></script>
</body>
</html>
index.html

app.js

這將包含咱們的應用程序的主要代碼。 首先要添加一個輔助函數來將消息記錄到<pre>: 

function log() {
    document.getElementById('results').innerText = '';

    Array.prototype.forEach.call(arguments, function (msg) {
        if (msg instanceof Error) {
            msg = "Error: " + msg.message;
        }
        else if (typeof msg !== 'string') {
            msg = JSON.stringify(msg, null, 2);
        }
        document.getElementById('results').innerHTML += msg + '\r\n';
    });
}
app.js

接下來,添加代碼將「click」事件處理程序註冊到三個按鈕:

document.getElementById("login").addEventListener("click", login, false);
document.getElementById("api").addEventListener("click", api, false);
document.getElementById("logout").addEventListener("click", logout, false);

接下來,咱們可使用oidc-client庫中的UserManager類來管理OpenID Connect協議。 它須要相似的配置,這在MVC客戶端中是必需的(雖然值不一樣)。 添加此代碼以配置和實例化UserManager:

var config = {
    authority: "http://localhost:5000",
    client_id: "js",
    redirect_uri: "http://localhost:5003/callback.html",
    response_type: "id_token token",
    scope:"openid profile api1",
    post_logout_redirect_uri : "http://localhost:5003/index.html",
};
var mgr = new Oidc.UserManager(config);

接下來,UserManager提供一個getUser API來知道用戶是否登陸到JavaScript應用程序。 它使用JavaScript Promise異步返回結果。 返回的用戶對象具備包含用戶聲明的配置文件屬性。 添加此代碼以檢測用戶是否已登陸JavaScript應用程序:

mgr.getUser().then(function (user) {
    if (user) {
        log("User logged in", user.profile);
    }
    else {
        log("User not logged in");
    }
});

接下來,咱們要實現登陸,api和註銷功能。 UserManager提供signinRedirect來登陸用戶,並提供signoutRedirect登陸用戶。 咱們在上面的代碼中得到的用戶對象也具備access_token屬性,可用於經過Web API進行身份驗證。 access_token將經過Bearer方案的Authorization頭傳遞給Web API。 添加此代碼以在咱們的應用程序中實現這三個功能:

function login() {
    mgr.signinRedirect();
}

function api() {
    mgr.getUser().then(function (user) {
        var url = "http://localhost:5001/identity";

        var xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.onload = function () {
            log(xhr.status, JSON.parse(xhr.responseText));
        }
        xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
        xhr.send();
    });
}

function logout() {
    mgr.signoutRedirect();
}

callback.html

一旦用戶登陸到IdentityServer,該HTML文件就是指定的redirect_uri頁面。 它將完成與IdentityServer的OpenID Connect協議登陸握手。 這個代碼所有由咱們以前使用的UserManager類提供。 登陸完成後,咱們能夠將用戶重定向回主index.html頁面。 添加此代碼以完成登陸過程:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <script src="oidc-client.js"></script>
    <script>
        new Oidc.UserManager().signinRedirectCallback().then(function () {
            window.location = "index.html";
        }).catch(function (e) {
            console.error(e);
        });
    </script>
</body>
</html>

爲JavaScript客戶端添加客戶端註冊到IdentityServer

如今客戶端應用程序已準備就緒,咱們須要在IdentityServer中爲這個新的JavaScript客戶端定義配置條目。 在IdentityServer項目中找到客戶端配置(在Config.cs中)。 爲咱們的新JavaScript應用程序添加一個新客戶端到列表中。 它應該具備下面列出的配置:

// JavaScript Client
new Client
{
    ClientId = "js",
    ClientName = "JavaScript Client",
    AllowedGrantTypes = GrantTypes.Implicit,
    AllowAccessTokensViaBrowser = true,

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

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1"
    }
}

容許使用CORS對Web API進行Ajax調用

須要配置的最後一點是在Web API項目中配置CORS。 這將容許Ajax調用從http://localhost:5003到http://localhost:5001。

Configure CORS

將CORS服務添加到Startup.cs中ConfigureServices中的依賴注入系統:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcCore()
        .AddAuthorization()
        .AddJsonFormatters();

    services.AddAuthentication("Bearer")
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;

            options.ApiName = "api1";
        });

    services.AddCors(options =>
    {
        // this defines a CORS policy called "default"
        options.AddPolicy("default", policy =>
        {
            policy.WithOrigins("http://localhost:5003")
                .AllowAnyHeader()
                .AllowAnyMethod();
        });
    });
}

在配置中將CORS中間件添加到管道中:

public void Configure(IApplicationBuilder app)
{
    app.UseCors("default");

    app.UseAuthentication();

    app.UseMvc();
}

 案例下載:https://pan.baidu.com/s/1wFDdwjmjWIhvMIPIoZQwBw

9、使用EntityFramework核心進行配置和操做數據

IdentityServer專爲擴展性而設計,其中一個可擴展點是用於IdentityServer所需數據的存儲機制。 本快速入門說明如何配置IdentityServer以使用EntityFramework(EF)做爲此數據的存儲機制(而不是使用咱們迄今爲止使用的內存中實現)。

IdentityServer4.EntityFramework

咱們正在向數據庫移動兩種類型的數據。 首先是配置數據(resources和client)。 第二個是IdentityServer在使用時生成的操做數據(tokens,codes和consents)。 這些商店使用接口建模,咱們在 IdentityServer4.EntityFramework  Nuget包中提供這些接口的EF實現。

經過添加對 IdentityServer4.EntityFramework  Nuget包的IdentityServer項目的引用開始。

使用SqlServer

鑑於EF的靈活性,您可使用任何EF支持的數據庫。 對於這個快速入門,咱們將使用Visual Studio附帶的SqlServer的LocalDb版本。

數據庫模式更改和使用EF遷移

IdentityServer4.EntityFramework軟件包包含從IdentityServer模型映射的實體類。 隨着IdentityServer的模型更改,IdentityServer4.EntityFramework中的實體類也會更改。 在使用IdentityServer4.EntityFramework並隨着時間的推移升級時,隨着實體類的更改,您將負責本身的數據庫模式以及對該模式所必需的更改。 管理這些變化的一種方法是使用EF遷移,這個快速入門將顯示如何完成。 若是遷移不是您的偏好,那麼您能夠以任何您認爲合適的方式管理架構更改。

用於遷移的EF工具

除了使用EF遷移跟蹤模式更改外,咱們還將使用它來建立數據庫中的初始模式。 這須要使用EF Core工具(更多細節在這裏)。 咱們如今將添加這些內容,不幸的是,這必須經過手工編輯您的.csproj文件來完成。 經過右鍵單擊項目並選擇「編輯projectname.csproj」來編輯.csproj: 

<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>

配置 stores

下一步是將當前調用替換爲Startup.cs中ConfigureServices方法中的AddInMemoryClients,AddInMemoryIdentityResources和AddInMemoryApiResources。 咱們將用下面的代碼替換它們:

const string connectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;database=IdentityServer4.Quickstart.EntityFramework-2.0.0;trusted_connection=yes;";
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddTestUsers(Config.GetUsers())
    // this adds the config data from DB (clients, resources)
    .AddConfigurationStore(options =>
    {
        options.ConfigureDbContext = builder =>
            builder.UseSqlServer(connectionString,
                sql => sql.MigrationsAssembly(migrationsAssembly));
    })
    // this adds the operational data from DB (codes, tokens, consents)
    .AddOperationalStore(options =>
    {
        options.ConfigureDbContext = builder =>
            builder.UseSqlServer(connectionString,
                sql => sql.MigrationsAssembly(migrationsAssembly));

        // this enables automatic token cleanup. this is optional.
        options.EnableTokenCleanup = true;
        options.TokenCleanupInterval = 30;
    });

您可能須要將這些命名空間添加到文件中:

using Microsoft.EntityFrameworkCore;
using System.Reflection;

上面的代碼是對鏈接字符串進行硬編碼的,若是你願意,你能夠隨意更改。 此外,對AddConfigurationStore和AddOperationalStore的調用正在註冊EF支持的存儲實現。

添加遷移

要建立遷移,請在IdentityServer項目目錄中打開命令提示符。 在命令提示符下運行這兩個命令:

dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb

您如今應該在項目中看到一個〜/Data/Migrations/IdentityServer文件夾。 這包含新建立的遷移的代碼。

初始化數據庫

如今咱們已經進行了遷移,咱們能夠編寫代碼來從遷移中建立數據庫。 咱們還將使用咱們在以前的快速入門中定義的內存配置數據對數據庫進行種子處理。

在Startup.cs中添加此方法以幫助初始化數據庫:

private void InitializeDatabase(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();

        var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
        context.Database.Migrate();
        if (!context.Clients.Any())
        {
            foreach (var client in Config.GetClients())
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.GetIdentityResources())
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.GetApiResources())
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

而後咱們能夠從Configure方法調用它::

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // this will do the initial DB population
    InitializeDatabase(app);

    // the rest of the code that was already here
    // ...
}

上面的InitializeDatabase幫助程序API能夠方便地爲數據庫建立種子,但這種方法並不適合每次運行應用程序時執行。 一旦你的數據庫被填充,考慮刪除對API的調用。

運行客戶端應用程序

您如今應該可以運行任何現有的客戶端應用程序並登陸,獲取令牌並調用API - 所有基於數據庫配置。

 

 案例下載:https://pan.baidu.com/s/1zVRXIEB9VMbbbCBf3kokTA

10、社區快速入門&樣品

各類ASP.NET core安全示例

https://github.com/leastprivilege/AspNetCoreSecuritySamples

IdentityServer4 EF 和 ASP.NET Identity

這個樣本結合了EF和ASP.NET身份快速入門(#6和#8)。

共同託管IdentityServer4和一個Web API

此示例顯示如何在保護API的IdentityServer所在的主機上託管API。

https://github.com/brockallen/IdentityServerAndApi

用於MongoDB的IdentityServer4案例

  • IdentityServer4-mongo:與快速入門#8 EntityFramework配置相似,但使用MongoDB做爲配置數據。 
  • IdentityServer4-mongo-AspIdentity:更詳細的示例基於使用ASP.NET身份進行身份管理,該身份管理使用MongoDB做爲配置數據

https://github.com/souzartn/IdentityServer4.Samples.Mongo

從Facebook,Google和Twitter交換外部令牌

演示如何使用擴展受權將外部身份驗證令牌交換到身份服務器訪問令牌

https://github.com/waqaskhan540/IdentityServerExternalAuth

IdentityServer4快速入門UI的ASP.NET Core MVC RazorPages模板

Razor Pages based QuickStart sample by Martin Fletcher.

.NET core和ASP.NET core「平臺」方案

顯示受信任的「內部」應用程序與「外部」應用程序與.NET Core 2.0和ASP.NET Core 2.0應用程序的交互

https://github.com/BenjaminAbt/Samples.AspNetCore-IdentityServer4

使用JWKS使用來自IdentityServer4的令牌保護Node API

  • 演示如何使用IdentityServer4的JWKS端點和RS256算法來保護Node(Express)API。
  • 使用更高質量的生產準備模塊爲IdentityServer4.Samples中的NodeJsApi樣本提供備選方案。

https://github.com/lyphtec/idsvr4-node-jwks

相關文章
相關標籤/搜索