asp.net core系列 54 IS4用客戶端憑據保護API

一. 概述

  本篇開始進入IS4實戰學習,從第一個示例開始,該示例是 「使用客戶端憑據保護API」,這是使用IdentityServer保護api的最基本場景。該示例涉及到三個項目包括:IdentityServer項目、API項目、Client項目,都有本身的宿主,爲了方便開發,放在了一個解決方案下(Quickstart.sln),三個項目的分工以下:html

         (1) IdentityServer項目是包含基本的IdentityServer設置的ASP.NET Core應用程序,是令牌端點。git

         (2) API項目是Web Api,是要保護的資源。github

         (3) Client項目是客戶端用戶,用來訪問Web Api。web

  最後客戶端Client項目請求獲取IdentityServer上的訪問令牌。做爲客戶端Client和IdentityServer都知道secret密鑰,Client將使用令牌訪問Web API。開源地址Githubapi

 

二. 建立IdentityServer項目 

  建立一個ASP.NET Core Web(或空)模板。項目名爲IdentityServer,解決方案爲Quickstart。是一個包含基本IdentityServer設置的ASP.NET Core應用程序。該項目使用的協議是http,當在Kestrel上運行時,端口設置爲5000或在IISExpress上的隨機端口。瀏覽器

  首次啓動時,IdentityServer將爲您建立一個開發人員簽名密鑰,它是一個名爲的文件tempkey.rsa。您沒必要將該文件檢入源代碼管理中,若是該文件不存在,將從新建立該文件。項目最終目錄結構以下所示:服務器

  下面進行說明,以及用序號來表示開發實現步驟:app

  2.1 安裝:Install-Package IdentityServer4async

  2.2 新增Config.cs文件, 該文件是IdentityServer資源和客戶端配置文件。在該文件中定義API資源,以及定義客戶端(能夠訪問此API的客戶端)ide

        /// <summary>
        /// 定義API資源,要保護的資源
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApis()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1", "My API")
            };
        }
        /// <summary>
        /// 定義客戶端,能夠訪問此API的客戶端
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId = "client",

                    // no interactive user, use the clientid/secret for authentication
                    AllowedGrantTypes = GrantTypes.ClientCredentials,

                    //使用密鑰進行身份認證  secret for authentication
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },

                    //客戶端容許訪問的範圍
                    AllowedScopes = { "api1" }
                }
            };
        }

  2.3 Startup配置    

        /// <summary>
        /// 配置IdentityServer,加載API資源和客戶端
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            // uncomment, if you wan to add an MVC-based UI
            //services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
             //添加AddIdentityServer
            var builder = services.AddIdentityServer()
                //添加內存的Identity資源
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                //添加api資源
                .AddInMemoryApiResources(Config.GetApis())
                 //添加clinet
                .AddInMemoryClients(Config.GetClients());

            if (Environment.IsDevelopment())
            {
          //開發環境下使用臨時簽名憑據 builder.AddDeveloperSigningCredential(); }
else { throw new Exception("need to configure key material"); } }
        public void Configure(IApplicationBuilder app)
        {
            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // uncomment if you want to support static files
            //app.UseStaticFiles();

            app.UseIdentityServer();

            // uncomment, if you wan to add an MVC-based UI
            //app.UseMvcWithDefaultRoute();
        }

  運行服務器並瀏覽瀏覽器 http://localhost:5000/.well-known/openid-configuration, 客戶端和API將使用它來下載必要的配置數據。下面是截取的部分配置數據:

 

三. 建立API項目

  在解決方案下繼續添加API項目,添加ASP.NET Core Web API(或空)模板。將API應用程序配置爲http://localhost:5001運行。項目最終目錄結構以下所示:

  (1) 在API項目中添加一個新文件夾Controllers和一個新控制器IdentityController

   //定義路由
    [Route("identity")]
    //須要受權
    [Authorize]
    public class IdentityController : ControllerBase
    {
        /// <summary>
        /// 測試受權,獲取該用戶下聲明集合Claims
        /// </summary>
        /// <returns></returns>
        public IActionResult Get()
        {
            return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
        }
    }

  (2) Startup配置

    public void ConfigureServices(IServiceCollection services)
        {
            //將最基本的MVC服務添加到服務集合中
            services.AddMvcCore()
                //向基本的MVC服務中添加受權
                .AddAuthorization()
                //向基本的MVC服務中添加格式化
                .AddJsonFormatters();

            //將身份驗證服務添加到DI服務集合中,並配置"Bearer"爲默認方案  
            services.AddAuthentication("Bearer")
                //驗證令牌是否有效用於此API
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "http://localhost:5000";
                    //在開發環境禁用,默認true
                    options.RequireHttpsMetadata = false;
            //訂閱者資源範圍 options.Audience
= "api1"; }); }
        public void Configure(IApplicationBuilder app)
        {
            //添加身份驗證中間件
            app.UseAuthentication();
            app.UseMvc();
        }

    啓動程序運行http://localhost:5001/identity時返回401狀態碼,未受權。意味着API須要憑證,如今受IdentityServer保護。以下所示:

 

四.建立Client項目

  咱們經過上面知道,直接用瀏覽器來訪問API是返回401狀態碼未受權,下面在Client項目中使用憑證,來得到api受權訪問。下面是Client項目目錄結構,這裏Client是一個控制檯應用程序。對於客戶端能夠是任意應用程序,好比手機端,web端,win服務等等。

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

  3.1  安裝:Install-Package IdentityModel

  3.2  發現IdentityServer端點

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

        private static async Task Main()
        {
            // discover endpoints from metadata
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
            if (disco.IsError)
            {
                //當停掉IdentityServer服務時
                //Error connecting to http://localhost:5000/.well-known/openid-configuration: 因爲目標計算機積極拒絕,沒法鏈接。
                Console.WriteLine(disco.Error);
                return;
            }
            //...

    其中GetDiscoveryDocumentAsync是屬於IdentityModel庫的,是對HttpClient擴展方法。http://localhost:5000是IdentityServer的基地址。

  3.3  請求令牌Token

    在Mian方法中繼續向IdentityServer請求令牌,訪問api1資源。這裏的RequestClientCredentialsTokenAsync方法也是HttpClient擴展方法。

            // request token,帶入須要的4個參數,請求令牌,返回TokenResponse
            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                //IdentityServer基地址 http://localhost:5000/connect/token
                Address = disco.TokenEndpoint,
                //設置客戶端標識
                ClientId = "client",
                //設置密鑰
                ClientSecret = "secret",
                //訪問的資源範圍
                Scope = "api1"
            });
            
            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                return;
            }
            //打印 token 信息
            Console.WriteLine(tokenResponse.Json);
            Console.WriteLine("\n\n");

  3.4 調用API

    在Mian方法中繼續向下,當訪問令牌取得後,開始調用Web API。 下面將訪問令牌發送到Web API,一般使用HTTP Authorization標頭。這是使用SetBearerToken擴展方法完成的,該方法是IdentityModel庫的HttpClient擴展方法。

            // call api
            var apiClient = new HttpClient();
            //發送訪問令牌
            apiClient.SetBearerToken(tokenResponse.AccessToken);

            //訪問API,獲取該用戶下聲明集合Claims
            var response = await apiClient.GetAsync("http://localhost:5001/identity");
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
            }
            else
            {
                //輸出 claims 名稱值 對
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }

    下面開始測試,先啓動IdentityServer程序,再啓動API程序,最後啓動Client客戶端來訪問API,經過下圖能夠了解到:(1)客戶端請求令牌成功,(2) 客戶端使用令牌來訪問API成功。

       若是想進一步嘗試激發錯誤,來了解系統的行爲,能夠錯誤的去配置以下:

    (1) 嘗試停掉IdentityServer服務程序,這個已經測試了。

    (2) 嘗試使用無效的客戶端ID標識  ClientId = "client",

    (3) 嘗試在令牌請求期間請求無效範圍 Scope = "api1"

    (4) 嘗試在API程序未運行時調用API

    (5) 嘗試不要將令牌發送到API

  

  總結:經過本篇瞭解到了IS4保護api的最基本場景。流程是首先建立一個IdentityServer 令牌程序。 接着建立API項目,使用IdentityServer令牌程序來保護API。 最後建立要訪問的Client項目,獲取訪問令牌後再調用API方法。

    IdentityServer令牌端對要保護API資源作了配置 new ApiResource("api1", "My API")

    限制了訪問Api的客戶端標識和訪問資源範圍ClientId = "client", AllowedScopes = { "api1" }還有客戶端須要的祕鑰。

 

  參考文獻

    使用客戶端憑據保護API

相關文章
相關標籤/搜索