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

一. 概述

本篇開始進入IS4實戰(zhàn)學(xué)習(xí),從第一個示例開始慧瘤,該示例是 “使用客戶端憑據(jù)保護API”戴已,這是使用IdentityServer保護api的最基本場景。該示例涉及到三個項目包括:IdentityServer項目锅减、API項目糖儡、Client項目,都有自己的宿主怔匣,為了方便開發(fā)握联,放在了一個解決方案下(Quickstart.sln),三個項目的分工如下:
(1) IdentityServer項目是包含基本的IdentityServer設(shè)置的ASP.NET Core應(yīng)用程序,是令牌端點金闽。
(2) API項目是Web Api纯露,是要保護的資源。
(3) Client項目是客戶端用戶代芜,用來訪問Web Api埠褪。

二. 創(chuàng)建IdentityServer項目

創(chuàng)建一個ASP.NET Core Web(或空)模板。項目名為IdentityServer,解決方案為Quickstart蜒犯。是一個包含基本IdentityServer設(shè)置的ASP.NET Core應(yīng)用程序组橄。該項目使用的協(xié)議是http,當(dāng)在Kestrel上運行時罚随,端口設(shè)置為5000或在IISExpress上的隨機端口玉工。
首次啟動時,IdentityServer將為您創(chuàng)建一個開發(fā)人員簽名密鑰淘菩,它是一個名為的文件tempkey.rsa遵班。您不必將該文件檢入源代碼管理中,如果該文件不存在潮改,將重新創(chuàng)建該文件狭郑。項目最終目錄結(jié)構(gòu)如下所示:



下面進行說明,以及用序號來表示開發(fā)實現(xiàn)步驟:
2.1 安裝:Install-Package IdentityServer4
2.2 新增Config.cs文件汇在, 該文件是IdentityServer資源和客戶端配置文件翰萨。在該文件中定義API資源,以及定義客戶端(可以訪問此API的客戶端)

/// <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()
                //添加內(nèi)存的Identity資源
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                //添加api資源
                .AddInMemoryApiResources(Config.GetApis())
                 //添加clinet
                .AddInMemoryClients(Config.GetClients());

            if (Environment.IsDevelopment())
            {
          //開發(fā)環(huán)境下使用臨時簽名憑據(jù)
                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();
        }

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

三. 創(chuàng)建API項目

在解決方案下繼續(xù)添加API項目,添加ASP.NET Core Web API(或空)模板阿蝶。將API應(yīng)用程序配置為http://localhost:5001運行雳锋。項目最終目錄結(jié)構(gòu)如下所示:


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

//定義路由
    [Route("identity")]
    //需要授權(quán)
    [Authorize]
    public class IdentityController : ControllerBase
    {
        /// <summary>
        /// 測試授權(quán)羡洁,獲取該用戶下聲明集合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服務(wù)添加到服務(wù)集合中
            services.AddMvcCore()
                //向基本的MVC服務(wù)中添加授權(quán)
                .AddAuthorization()
                //向基本的MVC服務(wù)中添加格式化
                .AddJsonFormatters();

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

啟動程序運行http://localhost:5001/identity時返回401狀態(tài)碼,未授權(quán)卧檐。意味著API需要憑證霉囚,現(xiàn)在受IdentityServer保護盈罐。如下所示:

四.創(chuàng)建Client項目

我們通過上面知道盅粪,直接用瀏覽器來訪問API是返回401狀態(tài)碼未授權(quán)票顾,下面在Client項目中使用憑證,來獲得api授權(quán)訪問含鳞。下面是Client項目目錄結(jié)構(gòu)蝉绷,這里Client是一個控制臺應(yīng)用程序。對于客戶端可以是任意應(yīng)用程序磁滚,比如手機端,web端晒他,win服務(wù)等等津滞。



 在IdentityServer的令牌端點實現(xiàn)了OAuth 2.0協(xié)議,客戶端可以使用原始HTTP來訪問它撞鹉。但是,我們有一個名為IdentityModel的客戶端庫颖侄,它將協(xié)議交互封裝在易于使用的API中鸟雏。
3.1 安裝:Install-Package IdentityModel
 3.2 發(fā)現(xiàn)IdentityServer端點

IdentityModel包括用于發(fā)現(xiàn)端點的客戶端庫。只需要知道IdentityServer的基地址 - 可以從元數(shù)據(jù)中讀取實際的端點地址:

private static async Task Main()
        {
            // discover endpoints from metadata
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
            if (disco.IsError)
            {
                //當(dāng)停掉IdentityServer服務(wù)時
                //Error connecting to http://localhost:5000/.well-known/openid-configuration: 由于目標(biāo)計算機積極拒絕览祖,無法連接孝鹊。
                Console.WriteLine(disco.Error);
                return;
            }
            //...

其中GetDiscoveryDocumentAsync是屬于IdentityModel庫的,是對HttpClient擴展方法穴墅。http://localhost:5000是IdentityServer的基地址惶室。
 3.3 請求令牌Token
在Mian方法中繼續(xù)向IdentityServer請求令牌,訪問api1資源玄货。這里的RequestClientCredentialsTokenAsync方法也是HttpClient擴展方法皇钞。

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

3.4 調(diào)用API
在Mian方法中繼續(xù)向下,當(dāng)訪問令牌取得后隘世,開始調(diào)用Web API可柿。 下面將訪問令牌發(fā)送到Web API,通常使用HTTP Authorization標(biāo)頭丙者。這是使用SetBearerToken擴展方法完成的复斥,該方法是IdentityModel庫的HttpClient擴展方法。

// call api
            var apiClient = new HttpClient();
            //發(fā)送訪問令牌
            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成功。



如果想進一步嘗試激發(fā)錯誤主儡,來了解系統(tǒng)的行為奖唯,可以錯誤的去配置如下:

(1) 嘗試停掉IdentityServer服務(wù)程序,這個已經(jīng)測試了糜值。

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

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

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

(5) 嘗試不要將令牌發(fā)送到API
 總結(jié):通過本篇了解到了IS4保護api的最基本場景丰捷。流程是首先創(chuàng)建一個IdentityServer 令牌程序坯墨。 接著創(chuàng)建API項目,使用IdentityServer令牌程序來保護API瓢阴。 最后創(chuàng)建要訪問的Client項目畅蹂,獲取訪問令牌后再調(diào)用API方法。

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

限制了訪問Api的客戶端標(biāo)識和訪問資源范圍ClientId = "client", AllowedScopes = { "api1" }還有客戶端需要的秘鑰荣恐。

參考文獻

使用客戶端憑據(jù)保護API

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市累贤,隨后出現(xiàn)的幾起案子叠穆,更是在濱河造成了極大的恐慌,老刑警劉巖臼膏,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硼被,死亡現(xiàn)場離奇詭異,居然都是意外死亡渗磅,警方通過查閱死者的電腦和手機嚷硫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來始鱼,“玉大人仔掸,你說我怎么就攤上這事∫角澹” “怎么了起暮?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長会烙。 經(jīng)常有香客問我负懦,道長,這世上最難降的妖魔是什么柏腻? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任纸厉,我火速辦了婚禮,結(jié)果婚禮上五嫂,老公的妹妹穿的比我還像新娘颗品。我一直安慰自己,他們只是感情好贫导,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布抛猫。 她就那樣靜靜地躺著,像睡著了一般孩灯。 火紅的嫁衣襯著肌膚如雪闺金。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天峰档,我揣著相機與錄音败匹,去河邊找鬼寨昙。 笑死,一個胖子當(dāng)著我的面吹牛掀亩,可吹牛的內(nèi)容都是我干的舔哪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼槽棍,長吁一口氣:“原來是場噩夢啊……” “哼捉蚤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炼七,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缆巧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后豌拙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陕悬,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年按傅,在試婚紗的時候發(fā)現(xiàn)自己被綠了捉超。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡唯绍,死狀恐怖拼岳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情推捐,我是刑警寧澤裂问,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站牛柒,受9級特大地震影響堪簿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜皮壁,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一椭更、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛾魄,春花似錦虑瀑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扔水,卻和暖如春痛侍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背魔市。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工主届, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赵哲,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓君丁,卻偏偏與公主長得像枫夺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子绘闷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容