1. 程式人生 > >使用Identity Server 4建立Authorization Server (3)

使用Identity Server 4建立Authorization Server (3)

上一部分簡單的弄了個web api 並通過Client_Credentials和ResourceOwnerPassword兩種方式獲取token然後進行api請求.

這次講一下Authentication 身份驗證 (而Authorization是授權, 注意區分), 使用的是OpenIdConnect.

這次我們使用的是一個MVC客戶端. 

建立MVC客戶端專案

在同一個解決方案建立一個名字叫MvcClient的asp.net core mvc 專案:

不要配置Authentication(身份驗證), 應該是沒有驗證.

修改執行方式為控制檯, 埠改為5002, 也就是修改launchSettings.json, 把IISExpress相關的去掉:

{
  "profiles": {
    "MvcClient": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5002/"
    }
  }
}

在HomeController的About方法上面新增Authorize屬性:

        [Authorize]
        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";

            return View();
        }

然後設定解決方案的啟動專案為MvcClient和Authorization Server, 解決方案右鍵屬性:

就會出現以下異常 (500):

我們現在要做的就是, 使用者點選About之後, 頁面重定向到Authorization Server, 使用者填寫完資訊之後登陸到Authorization Server之後再重定向回到該網站(MvcClient).

這也意味著使用者是在Authorization Server使用使用者名稱和密碼, 而MvcClient不儲存使用者的使用者名稱和密碼.

下面就開始配置

新增OpenId Connect Authentication

在Startup的ConfigureServices裡面新增:

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

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

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

                options.ClientId = "mvc_implicit";
                options.SaveTokens = true;
            });
        }

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 這句話是指, 我們關閉了JWT的Claim 型別對映, 以便允許well-known claims.

這樣做, 就保證它不會修改任何從Authorization Server返回的Claims.

AddAuthentication()方法是像DI註冊了該服務.

這裡我們使用Cookie作為驗證使用者的首選方式: DefaultScheme = "Cookies".

而把DefaultChanllangeScheme設為"oidc"是因為, 當用戶需要登陸的時候, 將使用的是OpenId Connect Scheme.

然後的AddCookie, 是表示添加了可以處理Cookie的處理器(handler).

最後AddOpenIdConnect是讓上面的handler來執行OpenId Connect 協議.

其中的Authority是指信任的Identity Server ( Authorization Server).

ClientId是Client的識別標誌. 目前Authorization Server還沒有配置這個Client, 一會我們再弄.

Client名字也暗示了我們要使用的是implicit flow, 這個flow主要應用於客戶端應用程式, 這裡的客戶端應用程式主要是指javascript應用程式. implicit flow是很簡單的重定向flow, 它允許我們重定向到authorization server, 然後帶著id token重定向回來, 這個 id token就是openid connect 用來識別使用者是否已經登陸了. 同時也可以獲得access token. 很明顯, 我們不希望access token出現在那個重定向中. 這個一會再說.

一旦OpenId Connect協議完成, SignInScheme使用Cookie Handler來發布Cookie (中介軟體告訴我們已經重定向回到MvcClient了, 這時候有token了, 使用Cookie handler來處理).

SaveTokens為true表示要把從Authorization Server的Reponse中返回的token們持久化在cookie中.

注意正式生產環境要使用https, 這裡就不用了.

接下來在Startup的Configure方法配置中介軟體, 以確保每次請求都執行authentication:

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

            app.UseAuthentication();

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

注意在管道配置的位置一定要在useMVC之前.

在Authorization Server新增Client

在Authorization Server的InMemoryConfiguration裡面新增Client:

public static IEnumerable<Client> Clients()
        {
            return new[]
            {
                new Client
                {
                    ClientId = "socialnetwork",
                    ClientSecrets = new [] { new Secret("secret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "socialnetwork" }
                },
                new Client
                {
                    ClientId = "mvc_implicit",
                    ClientName = "MVC Client",
                    AllowedGrantTypes = GrantTypes.Implicit,
                    RedirectUris = { "http://localhost:5002/signin-oidc" },
                    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
               "socialnetwork" } }
}; }

ClientId要和MvcClient裡面指定的名稱一致.

OAuth是使用Scopes來劃分Api的, 而OpenId Connect則使用Scopes來限制資訊, 例如使用offline access時的Profile資訊, 還有使用者的其他細節資訊. 

這裡GrantType要改為Implicit. 使用Implicit flow時, 首先會重定向到Authorization Server, 然後登陸, 然後Identity Server需要知道是否可以重定向回到網站, 如果不指定重定向返回的地址的話, 我們的Session有可能就會被劫持. 

RedirectUris就是登陸成功之後重定向的網址, 這個網址(http://localhost:5002/signin-oidc)在MvcClient裡, openid connect中介軟體使用這個地址就會知道如何處理從authorization server返回的response. 這個地址將會在openid connect 中介軟體設定合適的cookies, 以確保配置的正確性.

而PostLogoutRedirectUris是登出之後重定向的網址. 有可能發生的情況是, 你登出網站的時候, 會重定向到Authorization Server, 並允許從Authorization Server也進行登出動作.

最後還需要指定OpenId Connect使用的Scopes, 之前我們指定的socialnetwork是一個ApiResource. 而這裡我們需要新增的是讓我們能使用OpenId Connect的SCopes, 這裡就要使用Identity Resources. Identity Server帶了幾個常量可以用來指定OpenId Connect預包裝的Scopes. 上面的AllowedScopes設定的就是我們要用的scopes, 他們包括 openid Connect和使用者的profile, 同時也包括我們之前寫的api resource: "socialnetwork". 要注意區分, 這裡有Api resources, 還有openId connect scopes(用來限定client可以訪問哪些資訊), 而為了使用這些openid connect scopes, 我們需要設定這些identity resoruces, 這和設定ApiResources差不多:

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

然後我們需要配置Authorization Server來允許使用這些Identity Resources, Statup的:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer()
                //.AddDeveloperSigningCredential()
                .AddSigningCredential(new X509Certificate2(@"D:\Projects\test\socialnetwork.pfx", "[email protected]"))
                .AddInMemoryIdentityResources(InMemoryConfiguration.GetIdentityResources())
                .AddTestUsers(InMemoryConfiguration.Users().ToList())
                .AddInMemoryClients(InMemoryConfiguration.Clients())
                .AddInMemoryApiResources(InMemoryConfiguration.ApiResources());

            services.AddMvc();
        }

設定完了, 執行一下, 點選About選單就會重定向到Authorization Server:

注意看URL, 我們確實是在Authorization Server.

然後輸入使用者名稱密碼(TestUser的), 會看見一個請求允許的畫面:

可以看到網站請求了Profile資訊和User Identity. 

這個時候看上面選單處, 可以發現使用者已經成功登陸了Authorization Server:

所以這就允許我們做SSO(Single Sign-On) 單點登入了. 這時候其他使用這個Authorization Server的Client應用, 由於使用者已經登陸到Authorization Server了, 只需要請求使用者的許可來訪問使用者的資料就行了.

然後點選同意 Yes Allow, 就會重定向返回MvcClient網站的About頁面:

在View中顯示Claims

 開啟MvcClient的About.cshtml:

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

顯示所有使用者的Claims. Claims就是從Authorization Server返回的Payload裡面的資料.

執行進入About頁面:

嗯當前使用者有這些資訊....

想要從MvcClient呼叫WebApi

我們現在想從MvcClient呼叫WebApi的api/Values節點, 這就需要使用從Authorization Server返回的token. 但是由於我們使用的是implicit flow, 而使用implicit flow, 一切資料都是被髮送到Client的. 這就是說, 為了讓MvcClient知道使用者已經成功登陸了, Authorization Server將會告訴Client(Chrome瀏覽器)重定向回到MvcClient網站, 並附帶著資料. 這意味著token和其他安全資訊將會在瀏覽器裡面被傳遞. 也就是說從Authorization Server傳送access token的時候, 如果有人監聽的話就會看見這些資料, 使用ssl能有效阻止監聽到資料. 當然肯定有辦法解決這個問題, 例如使用其他flow. 但是有時候還是必須要使用implicit flow 獲取到access token. 我們需要做的就是告訴Authorization Server可以使用implicit flow來獲取token.

首先我們把token顯示出來:

@using Microsoft.AspNetCore.Authentication
<div>
    <strong>id_token</strong>
    <span>@await ViewContext.HttpContext.GetTokenAsync("id_token")</span>
</div>
<div>
    <strong>access_token</strong>
    <span>@await ViewContext.HttpContext.GetTokenAsync("access_token")</span>
</div>
<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

id_token是openid connect指定的, 你需要從authorization server獲得它, 用來驗證你的身份, 知道你已經登陸了. id_token不是你用來訪問api的.

access_token是用來訪問api的.

執行一下:

可以看到id_token有了, 而access_token沒有, 這是因為我們還沒有告訴Authorization Server在使用implicit flow時可以允許返回Access token.

修改Authorization Server的Client來允許返回Access Token

new Client
                {
                    ClientId = "mvc_implicit",
                    ClientName = "MVC Client",
                    AllowedGrantTypes = GrantTypes.Implicit,
                    RedirectUris = { "http://localhost:5002/signin-oidc" },
                    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        "socialnetwork"
                    },
                    AllowAccessTokensViaBrowser = true
                }

在某種情況下還是不建議這麼做.

然後在執行一下:

還是沒有access token. 這是因為我們需要重新登陸來獲取access token. 我們首先需要登出.

實現Logout 登出

在MvcClient的homeController新增方法:

        public async Task Logout()
        {
            await HttpContext.SignOutAsync("Cookies");
            await HttpContext.SignOutAsync("oidc");
        }

這裡需要確保同時登出本地應用(MvcClient)的Cookies和OpenId Connect(去Identity Server清除單點登入的Session).

然後就會跳轉到Identity Server的Logout了的頁面:

這寫到, 點選here可以返回到mvcclient.

點選here, 回到mvcclient, 然後點選About, 重新登陸. 同意, 重定向回來:

還是沒有access token.....

看看authorization server的控制檯:

有個地方寫到返回型別是id_token. 這表示我們要進行的是Authentication.

而我們想要的是既做Authentication又做Authorization. 也就是說我們既要id_token還要token本身.

這麼做, 在MvcClient的CongifureServices:

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

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

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

                options.ClientId = "mvc_implicit";
                options.ResponseType = "id_token token";
                options.SaveTokens = true;
            });
        }

然後重新執行, 退出, 重登入:

這次終於看到access_token了....

現在就可以使用access_token訪問api了.

先寫到這. 明後天繼續.

相關推薦

使用Identity Server 4建立Authorization Server (3)

上一部分簡單的弄了個web api 並通過Client_Credentials和ResourceOwnerPassword兩種方式獲取token然後進行api請求. 這次講一下Authentication 身份驗證 (而Authorization是授權, 注意區分), 使用的是OpenIdCon

使用Identity Server 4建立Authorization Server (2)

可能 參數 ecif fig register startup 類型 cal mat 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第一部分主要是建立了一個簡單的Identity Server. 接下來繼續: 建立Web

使用Identity Server 4建立Authorization Server (5)

連接字符串 mapr path 框架 ise network edit setting pin 預備知識: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780

使用Identity Server 4建立Authorization Server (6) - js(angular5) 客戶端

include 節點 ogr 包含 發的 for icon ets list 預備知識: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html

使用Identity Server 4建立Authorization Server (1)

官方文件很詳細的. 使用OAuth可以更安全, 這裡我們的authorization server和web api 以及網站將分別獨立執行.  建立authorization server 建立asp.net core 專案使用空模板. 專案建立後, 執行方式改為使用控制檯執行而不是IISEx

使用Identity Server 4建立Authorization Server (4)

上一篇講了使用OpenId Connect進行Authentication. 下面講 Hybrid Flow和Offline Access 目前我們解決方案裡面有三個專案 Authorization Server, Web api和Mvc Client. 在現實世界中, 他們可能都在不同

eShopOnContainers 看微服務③:Identity Service OAuth 2.0 簡介 OpenID Connect 簡介 Identity Server 4 eShopOnContainers 知多少[3]:Identity microservice

引言 通常,服務所公開的資源和 API 必須僅限受信任的特定使用者和客戶端訪問。那進行 API 級別信任決策的第一步就是身份認證——確定使用者身份是否可靠。 在微服務場景中,身份認證通常統一處理。一般有兩種實現形式: 基於API 閘道器中心化認證:要求客戶端必須都通過閘道器訪問微服務。(這就要求

ASP.NET Core3.1使用Identity Server4建立Authorization Server-1

# 前言 網上關於Identity Server4的資料有挺多的,之前是一直看楊旭老師的,最近專案中有使用到,在使用.NET Core3.1的時候有一些不同。所以在此記錄一下。 > 預備知識: https://www.cnblogs.com/cgzl/p/9405796.html > > 本文內容參考 >

ASP.NET Core3.1使用Identity Server4建立Authorization Server-2

# 前言 # 建立Web Api專案 在同一個解決方案下建立一個Web Api專案`IdentityServer4.WebApi`,然後修改Web Api的launchSettings.json。參考第一節,當然可以不修改的,埠號為`5001`。 ``` csharp { "profiles":

學習Identity Server 4的預備知識

發布 開發 簡單的 密碼 是否 alt imp load 通信 我要使用asp.net core 2.0 web api 搭建一個基礎框架並立即應用於一個實際的項目中去. 這裏需要使用identity server 4 做單點登陸. 下面就簡單學習一下相關的預備知識. 基於

要用Identity Server 4 -- OAuth 2.0 超級簡介

分隔 理解 大小 很多 應用程序 identity 復制 字符串 返回 OAuth 2.0 簡介 OAuth有一些定義: OAuth 2.0是一個委托協議, 它可以讓那些控制資源的人允許某個應用以代表他們來訪問他們控制的資源, 註意是代表這些人, 而不是假冒或模仿這些人

Identity Server 4 - Hybrid Flow - 保護API資源

還需 defaults rest 兩個 ade die tar try 意思 這個系列文章介紹的是Identity Server 4 的 Hybrid Flow, 前兩篇文章介紹了如何保護MVC客戶端, 本文介紹如何保護API資源. 保護MVC客戶端的文章: https:

一、sql server建立外來鍵約束有3中方式i

一、sql server中建立外來鍵約束有3中方式 1.Enterprise Manager中,Tables,Design Table,設定Table的properties, 可以建立constraint, reference key; 2.Enterprise Ma

學習Identity Server 4的預備知識 (誤刪, 重補)

我要使用asp.net core 2.0 web api 搭建一個基礎框架並立即應用於一個實際的專案中去. 這裡需要使用identity server 4 做單點登陸. 下面就簡單學習一下相關的預備知識. 基於Token的安全驗證體系 這個比較簡單, 簡單來說就是為了證明我們有訪問許可權, 我們首先需

Identity Server 4 (JWKS 端點和 RS256 演算法) 來保護 Python web api

目前正在使用asp.net core 2.0 (主要是web api)做一個專案, 其中一部分功能需要使用js客戶端呼叫python的pandas, 所以需要建立一個python 的 rest api, 我暫時選用了hug, 官網在這: http://www.hug.rest/. 目前專案使用的是ide

Identity Server 4

Claims 我不知道怎麼樣翻譯這個詞比較好, 所以我一般就不翻譯了. 在前一篇文章裡, MVC客戶端配置身份認證的時候有這麼一句話(Startup的ConfigureServices): JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Cl

Identity Server 4 預備知識 -- OAuth 2.0 簡介

OAuth 2.0 簡介 OAuth有一些定義: OAuth 2.0是一個委託協議, 它可以讓那些控制資源的人允許某個應用以代表他們來訪問他們控制的資源, 注意是代表這些人, 而不是假冒或模仿這些人. 這個應用從資源的所有者那裡獲得到授權(Authorization)和access token, 隨後就可

Identity Server 4 預備知識 -- OpenID Connect 簡介

這篇文章我要介紹一下 OpenID Connect. OAuth 2.0 不是身份認證協議 OAuth 2.0 不是身份認證(Authentication)協議. 為什麼有人會認為OAuth 2.0具有身份認證的功能? 這是因為OAuth2經常作為身份認證(Authentication)協議的一部分來

第44章 添加新協議 - Identity Server 4 中文文檔(v1.0.0)

iges author 重用 sign tsig dds mode 上下文 bool 除了對OpenID Connect和OAuth 2.0的內置支持之外,IdentityServer4還允許添加對其他協議的支持。 您可以將這些附加協議端點添加為中間件或使用例如MVC控制器

第47章 授權端點(Authorize Endpoint) - Identity Server 4 中文文檔(v1.0.0)

Nid str ons 響應 challenge redirect 授權 轉發 必須 授權端點可用於通過瀏覽器請求令牌或授權碼。此過程通常涉及最終用戶的身份驗證和可選的同意。 註意 IdentityServer支持OpenID Connect和OAuth 2.0授權請求參