基於IdentityServer4 實現.NET Core的認證授權


IdentityServer4是什么?

 IdentityServer4是基於ASP.NET Core實現的認證和授權框架,是對OpenID Connect和OAuth 2.0協議的實現。

OpenID Connect 和 OAuth2.0是什么

OpenID Connect:

OpenID Connect由OpenID基金會於2014年發布的一個開放標准, 是建立在OAuth 2.0協議上的一個簡單的身份標識層, OpenID Connect 兼容 OAuth 2.0. 實現身份認證(Authentication)
參考資料:https://openid.net/connect/
OpenID Connect文檔:https://openid.net/specs/openid-connect-discovery-1_0.html

OAuth2.0:

OAuth2.0是一個開放的工業標准的授權協議(Authorization),它允許用戶授權讓第三方應用直接訪問用戶在某一個服務中的特定資源,但不提供給第三方賬號及密碼信息
參考資料:https://www.cnblogs.com/xiandnc/p/9763121.html
OAuth2.0 文檔:https://tools.ietf.org/html/rfc6749#page-73

Authentication 和 Authorization的區別

authentication: n. 證明;鑒定;證實
authorization: n. 授權,認可;批准,委任

前者是身份識別,鑒別你是誰;后者是授權許可,告訴你可以做什么。
舉個例子:你吭哧吭哧寫了一天的代碼,急於回家吃上一口媳婦做的熱飯。當你走到小區門口的時候你需要刷小區的門禁卡才能進入到小區里面,然后再找到你家在哪一棟樓,幾單元幾號,然后掏出鑰匙開門才能回到家。在這個過程中刷小區的門禁就是認證你是這個小區的人,拿你家的鑰匙開門就是授權的過程,如果你的認證不通過,那就不存在授權。

OAuth2.0的原理

我們先來了解一下OAuth2.0中的幾個關鍵概念:

資源所有者(Resource Owner):

  一個能夠訪問受保護資源的實體。當資源所有者是一個人時,它被稱為終端用戶

資源服務器(Resource Server):

  托管受保護資源的服務器,能夠使用訪問令牌接受和響應受保護的資源請求

客戶端(Client):

  代表資源所有者和其授權的應用程序來保護資源請求。術語客戶端並不意味着任何特定的實現特征(例如,應用程序是否在服務器、桌面或其他設備上執行)

授權服務器(Authorization Server):

  在成功驗證資源所有者並獲得授權之后,服務器向客戶端發出訪問令牌。(授權服務器是用來管理Resource Owner,Resource Server,Client的中間人)

場景:小李想要打印(美圖快印)自己三年來發布在新浪微博相冊中和女朋友的照片,有沒有什么方法他既不告訴工作人員自己的新浪微博用賬號和密碼又能夠方便快捷的把照片給到美圖快印呢?(排除存U盤這種手工操作)

 

Authorization Server和Resource Server可以使獨立的服務提供商,也可以是在一起的,比如例子中新浪微博既作授權服務器也用來存儲用戶的圖片資源。我們可以看到OAuth2解決的問題是:通過Authorization Server可以提供一個訪問的憑據(token)給client(美圖快印的工作人員),使得client可以在不知道Resource Owner以及Resource Server的用戶名和密碼的情況下訪問到Resource Owner受保護的資源,它是一個完美的中間人。  

OAuth2.0詳細內容請參考:https://www.cnblogs.com/xiandnc/p/9763121.html

IdentityServer4能做什么

 

用戶認證服務

  基於OpenID Connect實現的獨立的認證服務實現對多平台(web, native, mobile, services)的集中認證

API訪問授權

  為各種類型的客戶機頒發api訪問令牌,例如服務器到服務器、web應用程序、spa和native/mobile程序

聯合身份認證

  支持外部身份提供者,如Azure Active Directory、Google、Facebook等

定制化的實現

  IdentityServer4的許多方面可以定制以滿足您的需要,因為它是一個框架,而不是SaaS服務,所以可以通過編寫代碼來調整實現,以適應不同的場景

成熟的開原方案

  使用許可的Apache2開源協議,允許在其之上構建商業產品,也作為.NET基金會支持的項目 (https://dotnetfoundation.org/projects?type=project&ps=10&pn=6

提供免費的商業支持

  官方可以對使用者提供部分的免費商業支持

IdentityServer4定義的基本術語

 

IdentityServer

  身份認證服務器是一個實現了OpenID Connect和OAuth 2.0協議的身份提供者,它負責向客戶端發布安全令牌

User

  使用注冊客戶端訪問資源的用戶

Client

        客戶端從標識服務器請求令牌,要么用於認證用戶(請求身份令牌),要么用於訪問資源(請求訪問令牌)
        客戶端必須首先在身份服務器上注冊,然后才能請求令牌
       這里的客戶端可以是web應用程序、native mobile, desktop applications, SPA 等程序


Resource
  資源是你想要用身份認證服務器保護的東西,如:用戶的身份數據或api
  每個資源都有一個惟一的名稱,客戶端使用這個名稱來指定他們想要訪問的資源
  關於用戶的身份數據標識(也稱為claim),例如姓名或電子郵件地址


Identity Token
  身份令牌代表身份驗證過程的結果


Access Token
  訪問令牌授權客戶端以允許訪問哪些API資源,訪問令牌包含客戶端和用戶的信息

 

IdentityServer4的簡單示例

 我們先來看一個簡單的例子,我們有三個API ,Order, Product, Inventory,我們利用IdentityServer4來實現對着三個API的認證和授權。首先我們需要一個實現認證和授權的服務,然后外部要想訪問我們的API就必須通過統一的認證和授權服務的任何才可以,否則就是返回401: UnAuthorized ,未經授權的訪問。我們既可以將身份信息存儲到內存中,也可以將其持久化到數據庫中,此處我們使用內存模式快速的演示實現(示例代碼中也支持存儲到DB中,使用SqlLite + EF Core)

首先我們需要安裝IdentityServer4的Nuget包,然后在ConfigureServices方法中添加如下代碼來初始化需要保護的API資源信息,代碼如下:

 

public void ConfigureServices(IServiceCollection services)
        {
            // config data in memory
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(InitMemoryData.GetApiResources())
                .AddInMemoryClients(InitMemoryData.GetClients())
                .AddTestUsers(InitMemoryData.GetUsers());

            // config in DB
            //services.AddDbContext<IdentityServerDbContext>(options =>
            //                            options.UseSqlite(sqliteConnection));
        }

 InitMemoryData 中的配置信息如下:

 // scopes define the API resources in your system
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("inventoryapi", "this is inventory api"),
                new ApiResource("orderapi", "this is order api"),
                new ApiResource("productapi", "this is product api")
            };
        }

        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            // client credentials client
            return new List<Client>
            {
                new Client
                {
                    ClientId = "inventory",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,

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

                    AllowedScopes = { "inventoryapi" }
                },
                 new Client
                {
                    ClientId = "order",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,

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

                    AllowedScopes = { "orderapi" }
                },
                 new Client
                {
                    ClientId = "product",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,

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

                    AllowedScopes = { "productapi" }
                }
            };
        }

我們給IdentityServer4設置啟動端口5000,認證服務的地址就是:http://localhost:5000 

然后認證Server端的代碼就好了,接下來我們需要在API添加授權服務的配置,配置都很類似,我們以OrderAPI為例: 

// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();

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

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();
            app.UseMvc();
        }

這里我們配置的Authority地址就是認證授權的地址,AddAuthentication中的Bearer是Jwt Token的一種,具體可參考文章:https://www.cnblogs.com/Leo_wl/p/7792046.html

在controller中添加簡單代碼來返回API的信息:

[Route("[controller]")]
    [Authorize]
    public class OrderController : ControllerBase
    {
        // GET api/order
        [HttpGet]
        public IActionResult Get()
        {
            var userIdentitys = from c in User.Claims
                                select new UserIdentity
                                {
                                    Type = c.Type,
                                    Value = c.Value
                                };
            var result = new UserIdentityModel()
            {
                Description = "Access user order api successfully",
                UserIdentitys = userIdentitys.ToList()
            };

            return new JsonResult(result);
        }
    }

設置當前API的端口為:5002

Product和Inventory中的配置和這個類似,端口信息以此設置為5001,5003,一切就緒,讓我們來測試一下結果:

啟動IdentotyServer,以及三個API,我們使用Postman來請求api,下面站點就是IdentityServer的頁面了:

接着我們來直接訪問OrderAPI就會發現返回 401 ,這說明目前我們的API已經受保護了,沒有認證服務頒發的token,是直接訪問不了的。

我們輸入地址:http://localhost:5000/.well-known/openid-configuration  可以查看我們當前認證授權服務的配置信息:

 

現在還差一步就可以訪問我們的OrderAPI了,那就是:客戶端傳入必要的信息給認證服務,生成一定格式的token,然后攜帶着這個token來訪問我們的服務 

 

傳入的三個參數分別是grant_type , client_sercret, client_id這幾個參數分別代表了我們申請token時的授權方式是客戶端授權,密匙,clientid信息。我們在前面介紹過IdentityServer4是對OAuth2.0的實現,所以具體參數的含義請參考之前OAuth2.0文章中的詳細介紹

https://www.cnblogs.com/xiandnc/p/9763121.html

此時我們可以看到認證服務給我們返回了有效token,指定過期時間3600s ,token的類型是Bearer,然后我們再攜帶這這個token去訪問服務試試看:

 

我們可以看到此時API 返回了我們期待的正確結果,如果在1小時后再攜帶着這個token去訪問API就會提示token已過期,需要重新生成才能夠繼續訪問。看完這個例子是不是很簡單,很清爽呢

例子參考代碼:https://github.com/KenWang007/IdentityServer4Demo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM