Identity Server4學習系列三

一、簡介html

Identity Server4學習系列一Identity Server4學習系列二之令牌(Token)的概念的基礎上,瞭解了Identity Server4的由來,以及令牌的相關知識,本文開始實戰,實現Identity Server4基本的功能。編程

 

二、前提api

本文基於.Net Core2.1和Indetity Server4 2.3.0,令牌處理包採用IdentityServer4.AccessTokenValidation 2.7.0瀏覽器

 

三、實戰一Identity Server4服務端配置服務器

(1)、項目結構session

 

(2)、站點入口文件Program.cs類mvc

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        /// <summary>
        /// 設置當前項目的服務器宿主,Windows下默認爲IIS
        /// 設置啓動類爲Startup類
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }

注意:若是時Linux環境,這裏在這裏能夠切換站點的宿主服務器app

 

(3)、Startup啓動類(配置Identity Server4的相關參數和MVC的相關參數,並注入到管道模型中)異步

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            //優雅的鏈式編程
            //注入Identity Server4服務到DI容器中
            services.AddIdentityServer()
           //注入臨時簽名憑據到DI容器,後期可用簽名證書的密鑰替換,用於生成零時密鑰
           .AddDeveloperSigningCredential()
           //注入須要受Identity Server4保護的Api資源添注入到DI容器中 -內存級別
           .AddInMemoryApiResources(Apis.GetApiResources())
           //注入須要訪問受Identity Server4保護的Api資源的客戶端注入到DI容器中 -內存級別
           .AddInMemoryClients(ThirdClients.GetClients());

            //注入基本的MVC服務
            services.AddMvcCore()
            //注入MVC的認證服務,對應控制器的Authorize特性
           .AddAuthorization()
           //注入MVC格式化程序,對應JsonResult等等的格式化操做,主要用於控制器返回值的格式化操做
           .AddJsonFormatters();

            //注入身份認證服務,設置Bearer爲默認方案
            services.AddAuthentication("Bearer")
            //注入並配置Bearer爲默認方案的基本參數
            .AddIdentityServerAuthentication(options =>
            {
                //設置令牌的發佈者
                options.Authority = "http://localhost:5000";
                //設置Https
                options.RequireHttpsMetadata = false;
                //須要認證的api資源名稱
                options.ApiName = "api1";
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //若是當前時開發者模式
            if (env.IsDevelopment())
            {
                //從管道中捕獲同步和異步System.Exception實例並生成HTML錯誤響應。
                app.UseDeveloperExceptionPage();
            }

            //將IdentityServer 4服務注入到管道模型中(對應上面的IdentityServer 4服務的配置)
            app.UseIdentityServer();

            //將認證服務經過Microsoft.AspNetCore.Authentication.AuthenticationMiddleware中間件
            //注入到管道模型中(對應上面認證服務的配置)
            app.UseAuthentication();

            //將mvc添加到Microsoft.AspNetCore.Builder.IApplicationBuilder請求執行中(對應上的MVC配置)
            app.UseMvc();
        }
    }

 

(4)、配置第三方客戶端能成功在認證模式下能成功訪問Api資源的資本參數async

    /// <summary>
    /// 配置能夠訪問IdentityServer4 保護的Api資源模型的第三方客戶端
    /// 配置客戶端訪問的密鑰
    /// 配置
    /// </summary>
    public class ThirdClients
    {
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>()
            {
                new Client()
                {
                    //客戶端的惟一Id,客戶端須要指定該ClientId才能訪問
                     ClientId = $"client",

                    //no interactive user, use the clientid/secret for authentication
                    //使用客戶端密鑰進行認證
                    AllowedGrantTypes = GrantTypes.ClientCredentials,

                    // 認證密鑰
                    ClientSecrets =
                    {
                        //用Sha256對"secret"進行加密,客戶端必須使用secret密鑰才能成功訪問
                        new Secret("secret".Sha256())
                    },

                    // scopes that client has access to
                    //若是客戶端的密鑰認證成功,限定該密鑰能夠訪問的Api範圍
                    AllowedScopes = { "api1" }
                }
            };
        }
    }

注意ClientId(分配給不一樣客戶端的Id),對應的客戶端調用時傳遞過來的ClientId必須一致,不然客戶端發起調用時彙報這個錯:

密鑰也是同樣,密鑰是咱們分配給客戶端的,客戶端只有給對了咱們分配給它的ClientId和密鑰的同時,才能訪問對應的api,因此若是你的密鑰不對,客戶端發起調用時也會報這個錯:

 

(5)、配置受保護的Api資源模型

    public class Apis
    {
        //ApiResource -IdentityServer4.Models下的Api資源模型
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>()
            {
                //Api資源模型
                new ApiResource("api1", "My API")
            };
        }
    }

注意ApiRescourse的名稱必須和Client的AllowedScopes屬性對應,不然客戶端調用時會報下面這個錯:

 

(6)、驗證服務端是否配置成功

開啓站點,瀏覽器輸入http://localhost:5000/.well-known/openid-configuration,等到以下返回報文說明服務部署成功:

{
   //令牌簽發者,對應StartUp中的Identity Server4中的認證配置
"issuer":"http://localhost:5000",
//jwt令牌處理地址
"jwks_uri":"http://localhost:5000/.well-known/openid-configuration/jwks", "authorization_endpoint":"http://localhost:5000/connect/authorize", "token_endpoint":"http://localhost:5000/connect/token", "userinfo_endpoint":"http://localhost:5000/connect/userinfo", "end_session_endpoint":"http://localhost:5000/connect/endsession", "check_session_iframe":"http://localhost:5000/connect/checksession", "revocation_endpoint":"http://localhost:5000/connect/revocation", "introspection_endpoint":"http://localhost:5000/connect/introspect", "device_authorization_endpoint":"http://localhost:5000/connect/deviceauthorization", "frontchannel_logout_supported":true, "frontchannel_logout_session_supported":true, "backchannel_logout_supported":true, "backchannel_logout_session_supported":true, "scopes_supported":[ "api1", "offline_access" ], "claims_supported":[ ], "grant_types_supported":[ "authorization_code", "client_credentials", "refresh_token", "implicit", "urn:ietf:params:oauth:grant-type:device_code" ], "response_types_supported":[ "code", "token", "id_token", "id_token token", "code id_token", "code token", "code id_token token" ], "response_modes_supported":[ "form_post", "query", "fragment" ], "token_endpoint_auth_methods_supported":[ "client_secret_basic", "client_secret_post" ], "subject_types_supported":[ "public" ], "id_token_signing_alg_values_supported":[ "RS256" ], "code_challenge_methods_supported":[ "plain", "S256" ] }

參數含義,自行了解

 

三、實戰一客戶端調用受Identity Server4保護的Api資源

(1)、前提

客戶端必須安裝IdentityModel 3.10.4包

 

(2)、調用代碼以下:

    class Program
    {
        static void Main(string[] args)
        {
            Request();
            Console.ReadKey();
        }

        async static void Request()
        {
            //請求Identity Server4服務
            var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }
            //生成Identity Server4受權的客戶端,經過指定對應的ClientId和密鑰(secret)
            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);

            //經過Identity Server4的認證事後,拿到AccessToken
            var client = new HttpClient();
            client.SetBearerToken(tokenResponse.AccessToken);
            var response = await client.GetAsync("http://localhost:5000/identity");
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
            }
            else
            {
                //認證成功,輸出Identity控制器的返回值
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }
        }
    }

獲得以下報文:

同時查看Identity Server4服務端的輸出:

第一步:客戶端傳入在Indetity Server4中註冊過的分配給該客戶端的ClientId和密鑰,拿到AccessToken

 

第二步:第一次請求目標控制器,並把AcessToken帶過去

第三步:驗證Token是否有效

第四步:Token有效,開始調用Identity控制器方法,並拿到響應值

 大體的流程如上.

相關文章
相關標籤/搜索