NET 5 使用IdentityServer4 4.x


一.簡介

官方文檔https://identityserver4.readthedocs.io/en/latest/

IdentityServer4是一個框架,IdentityServer4是為ASP.NET CORE量身定制的實現了OpenId Connect和OAuth2.0協議的認證授權中間件。OpenId用於身份認證(Authentication) OAuth2.0 用於授權(Authorization)  OpenId Connect = OIDC = (Identity, Authentication) + OAuth2.0

IdentityServer4功能特性

  • Authentication as a Service:可以為你的應用(如網站、本地應用、移動端、服務)做集中式的登錄邏輯和工作流控制。IdentityServer是完全實現了OpenID Connect協議標准
  • Single Sign-on / Sign-out:在多個應用程序類型上進行單點登錄(和單點退出)。
  • Access Control for APIs:為不同類型的客戶端,例如服務器到服務器、web應用程序、SPAs和本地/移動應用程序,發出api的訪問令牌。
  • Federation Gateway:支持來自Azure Active Directory, Google, Facebook這些知名應用的身份認證,可以不必關心連接到這些應用的細節就可以保護你的應用。
  • Focus on Customization:最重要的是identityserver可以根據需求自行開發來適應應用程序的變化。identityserver不是一個框架、也不是一個盒裝產品或一個saas系統,您可以編寫代碼來適應各種場景。

IdentityServer是將規范兼容的OpenID Connect和OAuth 2.0端點添加到任意ASP.NET Core應用程序的中間件。通常,您構建(或重新使用)包含登錄和注銷頁面的應用程序,IdentityServer中間件會向其添加必要的協議頭,以便客戶端應用程序可以與其對話 使用這些標准協議。

IdentityServer4 默認支持兩種類型的 Token,一種是 Reference Token,一種是 JWT Token 。前者的特點是 Token 的有效與否是由 Token 頒發服務集中化控制的,頒發的時候會持久化 Token,然后每次驗證都需要將 Token 傳遞到頒發服務進行驗證,是一種中心化的比較傳統的驗證方式。JWT Token 的特點與前者相反,每個資源服務不需要每次都要都去頒發服務進行驗證 Token 的有效性驗證,該 Token 由三部分組成,其中最后一部分包含了一個簽名,是在頒發的時候采用非對稱加密算法(最新的JWT Token)進行數據簽名的,保證了 Token 的不可篡改性,保證了安全,與頒發服務的交互,僅僅是獲取公鑰用於驗證簽名,且該公鑰獲取以后可以自己緩存,持續使用,不用再去交互獲得,除非Token包含的 keyid 對應的 公鑰沒被緩存(新的),就會再次向頒發服務獲取。流程圖:

二.identity server4 五種授權模式

下面介紹4種模式安全性從低到高

客戶端模式

客戶端模式只對客戶端進行授權,不涉及到用戶信息。如果你的api需要提供到第三方應用,第三方應用自己做用戶授權,不需要用到你的用戶資源,就可以用客戶端模式,只對客戶端進行授權訪問api資源。

這是一種最簡單的模式,只要client請求,我們就將AccessToken發送給它。這種模式是最方便但最不安全的模式。因此這就要求我們對client完全的信任,而client本身也是安全的

密碼模式

需要客戶端提供用戶名和密碼,密碼模式相較於客戶端憑證模式。通過User的用戶名和密碼向Identity Server申請訪問令牌。

如果你高度信任某個應用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應用

(授權碼)隱藏模式

密碼模式將用戶的密碼暴露給了客戶端,這無疑是不安全的,隱藏模式可以解決這個問題,由用戶自己在IdentityServer服務器進行登錄驗證,客戶端不需要知道用戶的密碼。

有些 Web 應用是前后端分離的純前端應用,沒有后端。這時就不能用上面的授權碼模式了,必須將令牌儲存在前端。

這種方式沒有授權碼這個中間步驟,所以稱為(授權碼)"隱藏式"(implicit)。

一般用的這個,token會直接返回到訪問的地方,適用於前后端分離的項目(前后端分離后,只能把token保存到前端了,為他只有前端沒有服務器)

授權碼模式

授權碼模式隱藏碼模式最大不同是授權碼模式不直接返回token,而是先返回一個授權碼,然后再根據這個授權碼去請求token。這比隱藏模式更為安全。從應用場景上來區分的話,隱藏模式適應於全前端的應用,授權碼模式適用於有后端的應用,因為客戶端根據授權碼去請求token時是需要把客戶端密碼轉進來的,為了避免客戶端密碼被暴露,所以請求token這個過程需要放在后台

混合模式(Hybrid),就是基於隱藏模式與授權碼模式的結合

OpenIdConnect是OAuth2.0與OpenId的結合,並加入了一個重要的概念:id_token。我們之前所講的token是用於訪問授權的access_token,而id_token是用於身份驗證的,作用完全不同,這一點要區分開來。access_token是OAth2.0特性,而id_token是OpenIdConnect方案為改善OAuth2.0方案在身份驗證方面的薄弱而加入的特性。

客戶端獲取Id_token與隱藏模式和授權碼模式一樣,都是通過redirect_url參數返回的,所以前面的四種模式中的客戶端模式與密碼模式不支持獲取id_token,而授權碼模式受限於流程,必需先取得Code才能取到token,所以不能直接支持獲取id_token,如果需求是使用授權碼模式,同時又需要id_token,OpenIdConnect支持第五種模式:混合模式(Hybrid),就是基於隱藏模式與授權碼模式的結合

三.使用

IdentityService4(簡稱is4)有兩種初始化方式:

1使用命令行安裝is4模板

  1)安裝模板命令:dotnet new -i IdentityServer4.Templates

  2)安裝完成之后執行dotnet new命令如下圖所示多出了一些模板

  3)使用dotnet new is4empty -n IdentityServer創建一個is4empty模板,is4項目初始化完成

2.手動建立

1、創建ASP.NET Core Web應用程序,選擇MVC。

2、添加nuget包:IdentityServer4。

 3、添加Config.cs文件作為IdentityServer配置文件,用於定義IdentityServer資源和客戶端等。

using IdentityModel;
using IdentityServer4;
using IdentityServer4.Models;
using IdentityServer4.Test;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace WebApplication10
{
    public class OAuthConfig
    {
        /// <summary>
        /// token有效時間 過期秒數 //2小時 = 3600 * 2
        /// </summary>
        public static int ExpireIn = 3600;

        /// <summary>
        /// 跨域地址
        /// </summary>

        public static string[] CorUrls = new[] { "http://*:4137", "http://*:5072" };

        /// <summary>
        /// Api資源名稱
        /// </summary>

        public static string ApiName = "user_api";

        /// <summary>
        /// 客戶端唯一ID
        /// </summary>

        public static string ClientId = "user_clientid";

        /// <summary>
        /// 密鑰
        /// </summary>

        public static string Secret = "user_secret";
    }
    /// <summary>
    ///  密碼授權模式  分資源分為身份資源(Identity resources)和API資源(API resources)。
    /// </summary>
    public class Config
    {
        #region 定義資源
        // 身份信息授權資源
        public static IEnumerable<IdentityResource> GetIdentityResources() =>
            new IdentityResource[]
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile()
            };

        //API訪問授權資源
        public static IEnumerable<ApiResource> GetApiResources() =>
            new ApiResource[]
            {
                //標識名稱  顯示名稱(自定義)
                new ApiResource(OAuthConfig.ApiName,"我的Ids4")
                {
                    UserClaims =  { ClaimTypes.Name, JwtClaimTypes.Name },
                    ApiSecrets = new List<Secret>()
                    {
                        new Secret(OAuthConfig.Secret.Sha256())
                    }
                }
            };
        #endregion

        #region 定義客戶端Client
        /// <summary>
        /// 4種模式 客戶端模式(ClientCredentials) 密碼模式(ResourceOwnerPassword)  隱藏模式(Implicit)  授權碼模式(Code)
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients() =>
            new Client[]
            {
                 new Client
                {
                    ClientId = OAuthConfig.ClientId,//客戶端的唯一ID
                    ClientName = "隱式模式",//客戶端顯示名稱
                    AllowedGrantTypes = GrantTypes.Implicit,// 隱式模式
                    ClientSecrets = new []{ new Secret(OAuthConfig.Secret.Sha256()) },//客戶端加密方式
                    RequireConsent = false, //如果不需要顯示否同意授權 頁面 這里就設置為false  
                    AllowAccessTokensViaBrowser = true,//控制是否通過瀏覽器傳輸此客戶端的訪問令牌
                    AccessTokenLifetime = OAuthConfig.ExpireIn, //過期秒數
                    //登錄成功跳轉地址
                    RedirectUris =
                    {
                        "http://localhost:4137/oauth2-redirect.html",
                    },
                    //退出登錄跳轉地址
                    PostLogoutRedirectUris =
                    {
                        $"http://www.taobao.com"
                    },
                    //跨域地址
                    AllowedCorsOrigins = OAuthConfig.CorUrls,
                    //配置授權范圍,這里指定哪些API 受此方式保護
                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        OAuthConfig.ApiName
                    }
                }
            };
        #endregion


        /// <summary>
        /// 測試的賬號和密碼
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser>
            {
                new TestUser()
                {
                     SubjectId = "1",
                     Username = "admin",
                     Password = "123456"
                },
                new TestUser()
                {
                     SubjectId = "2",
                     Username = "test",
                     Password = "123456"
                }
            };
        }
    }
}
View Code

4.配置Startup

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Admin.IdentityServer.Account;
using IdentityServer4.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace WebApplication10
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        private string basePath => AppContext.BaseDirectory;

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var builder = services.AddIdentityServer(options =>
            {
                options.UserInteraction = new UserInteractionOptions
                {
                    LoginUrl = "/user/login",
                    LogoutUrl = "/user/logout"
                };
            })
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiResources(Config.GetApiResources())//把受保護的Api資源添加到內存中
                .AddInMemoryClients(Config.GetClients())//客戶端配置添加到內存中

               .AddProfileService<AdminProfileService>()
               .AddResourceOwnerValidator<AdminResourceOwnerPasswordValidator>();


            //添加證書加密方式,執行該方法,會先判斷tempkey.rsa證書文件是否存在,如果不存在的話,就創建一個新的tempkey.rsa證書文件,如果存在的話,就使用此證書文件
            builder.AddDeveloperSigningCredential();

            #region Cors 跨域
            services.AddCors(options =>
            {
                options.AddPolicy("Limit", policy =>
                {
                    policy
                    .WithOrigins(OAuthConfig.CorUrls)
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
                });
            });
            #endregion
            services.AddControllersWithViews();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseCors("Limit");

            app.UseStaticFiles();

            app.UseRouting();

            //啟動ids4中間件
            app.UseIdentityServer();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

        }
    }
}
View Code

5.配置服務端

services.AddAuthentication("Bearer")
           .AddIdentityServerAuthentication(options =>
           {
               options.Authority = "http://localhost:4137";    //配置Identityserver的授權地址
               options.RequireHttpsMetadata = false;           //不需要https    
               options.ApiName = "user_api";  //api的name,需要和config的名稱相同
           });
View Code

 

參考地址 IdentityServer4之Implicit和純前端好像很配哦 https://github.com/zyq025/IDS4Demo

IdentityServer4 統一授權認證系統

live-server安裝

npm install -g live-server

live-server
live-server運行在8080端口下,可以通過127.0.0.1:8080來訪問靜態頁面。

npm install --save live-server-https

這是https

 


免責聲明!

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



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