IdentityServer4 快速上手


IdentityServer4 是一個基於 .NET Core 的 OpenID Connect 實現框架。

基於框架創建可運行的應用,通常還需要多個步驟,添加引用、配置項目、框架初始化、按照一系列步驟啟動應用等等。那么,基於 IdentityServer4 創建一個可運行的 OpenID Connect 服務器需要多少行代碼呢?

得益於 .net core 提供的項目模版支持,實際上,不需要你寫一行代碼,只需要執行幾個簡單的命令就可以了。

1. 准備 IdentityServer4 模版

還記得使用 .net core 的命令行工具 dotnet 創建項目使用的 new 命令嗎?如果你希望創建名為 HelloWorld 的項目,那么,創建它的命令如下:

dotnet new console -n HelloWorld

該命令會在當前目錄下創建 HelloWorld 子目錄。命令執行完成之后,進入這個 HelloWorld 目錄中,就可以通過 run 命令來運行了。

>cd HelloWorld
>dotnet run
Hello World!

這個 console 就是通過內置的模版來實現的。當前支持的模版可以通過 list 子命令列出

dotnet new -list

在 dotnet 中,還可以通過 -i 參數來安裝新的模版。模版既可以通過一個路徑提供,也可以通過一個 nuget_id 來提供。你可能已經想到了,IdentityServer4 就已經提供了一個預定義在 NuGet 中的模版:IdentityServer4.Templates,你可以直接在 NuGet 中找到它:https://www.nuget.org/packages/IdentityServer4.Templates。需要說明的是,同一個項目模版可能存在多個版本,在安裝的時候,可以通過在模版名稱后面使用兩個冒號來分隔特定的版本號,默認情況下,只安裝最新的穩定版本。

所以,事情變得簡單了。我們需要的就是先在本地安裝這個模版,然后,使用這個模版就可以直接創建出完整的 IdentityServer4 項目,然后直接運行。

dotnet new --install IdentityServer4.Templates

NuGet 中的提示是安裝特定的版本,現在的最新穩定版本是 3.1.1,所以命令變成了

dotnet new --install IdentityServer4.Templates::3.1.1

在命令的輸出中,可以看到已經安裝了多個關於 IdentityServer4 的模版

Templates Short Name Language Tags
IdentityServer4 with AdminUI is4admin [C#] Web/IdentityServer4
IdentityServer4 with ASP.NET Core Identity is4aspid [C#] Web/IdentityServer4
IdentityServer4 Empty is4empty [C#] Web/IdentityServer4
IdentityServer4 with Entity Framework Stores is4ef [C#] Web/IdentityServer4
IdentityServer4 with In-Memory Stores and Test Users is4inmem [C#] Web/IdentityServer4
IdentityServer4 Quickstart UI (UI assets only) is4ui [C#] Web/IdentityServer4

這里面最為簡單的項目模版就是 IdentityServer4 Empty 了,它簡稱為 is4empty ,我們下面就使用它來創建項目。

2. 創建第一個 IdentityServer4 項目

直接使用 .net core 的 new 命令來創建項目,我們將創建的項目命名為 IdentityServer

dotnet new is4empty -n IdentityServer

執行之后,會在當前目錄下創建 IdentityServer 文件夾,所有的項目文件都位於其中。

3. 啟動應用

使用 .net core 的 run 命令來啟動項目,可以看到如下輸出:

dotnet new is4empty -n IdentityServer
PS C:\temp\is4\IdentityServer> dotnet run
[19:34:49 Information]
Starting host...
​
[19:34:50 Information] IdentityServer4.Startup
Starting IdentityServer4 version 3.1.0.0
​
[19:34:50 Information] IdentityServer4.Startup
You are using the in-memory version of the persisted grant store. This will store consent decisions, authorization codes, refrtion.
​
[19:34:50 Information] IdentityServer4.Startup
Using the default authentication scheme idsrv for IdentityServer
​
[19:34:50 Debug] IdentityServer4.Startup
Using idsrv as default ASP.NET Core scheme for authentication
​
[19:34:50 Debug] IdentityServer4.Startup
Using idsrv as default ASP.NET Core scheme for sign-in
​
[19:34:50 Debug] IdentityServer4.Startup
Using idsrv as default ASP.NET Core scheme for sign-out
​
[19:34:50 Debug] IdentityServer4.Startup
Using idsrv as default ASP.NET Core scheme for challenge
​
[19:34:50 Debug] IdentityServer4.Startup
Using idsrv as default ASP.NET Core scheme for forbid

祝賀你!你已經成功創建了第一個可運行的 IdentityServer4 服務器!

4. 訪問配置信息

雖然還沒有寫一行代碼,但是,服務器已經在工作了,我們可以通過它的 .well-known 端點來訪問服務器的配置信息,在瀏覽器的地址欄中,輸入地址:http://localhost:5000/.well-known/openid-configuration,並回車。應該可以看到如下的響應信息。 

{
    "issuer": "http://localhost:5000",
    "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": [
        "openid",
        "offline_access"
    ],
    "claims_supported": [
        "sub"
    ],
    "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"
    ],
    "id_token_signing_alg_values_supported": [
        "RS256"
    ],
    "subject_types_supported": [
        "public"
    ],
    "code_challenge_methods_supported": [
        "plain",
        "S256"
    ],
    "request_parameter_supported": true
}

 5. 查看項目代碼

5.1 項目文件

項目文件名稱為 IdentityServer4.csproj,內容如下:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="IdentityServer4" Version="3.1.0" />
    <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
    <!-- <PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" /> -->
  </ItemGroup>
</Project>

主要做了 3 件事:

  • 配置了項目為 Web 應用項目,通過 Sdk 屬性指定了 Microsoft.NET.Sdk.Web,目標框架為 .net core 3.1。

  • 添加了對 IdentityServer4 的引用,這就是 IdentityServer4 的實現庫

  • 添加了日志庫 Serilog.AspNetCore

5.2 Program.cs

這里面相當多的代碼是關於 Serilog 日志的配置,關於 Web 站點,只是使用了標准的 Startup 方式啟動。

// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
​
​
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;
using System;
​
namespace IdentityServer
{
    public class Program
    {
        public static int Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
                .MinimumLevel.Override("System", LogEventLevel.Warning)
                .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
                .Enrich.FromLogContext()
                .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate)
                .CreateLogger();
​
            try
            {
                Log.Information("Starting host...");
                CreateHostBuilder(args).Build().Run();
                return 0;
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly.");
                return 1;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
​
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseSerilog();
                });
    }
}

5.3 Startup.cs

在 ConfigureServices() 中,最為關鍵的一行就是添加了 IdentityServer4 服務的支持。

由於這是用於演示的空項目,所以,具體的 OpenID Connect 配置信息來自於一個代碼文件 Config,並使用硬編碼的方式來用於 IdentityServer

var builder = services.AddIdentityServer()
  .AddInMemoryIdentityResources(Config.Ids)
  .AddInMemoryApiResources(Config.Apis)
  .AddInMemoryClients(Config.Clients);

這個 Config.cs 文件中,還沒有對這些信息進行配置。

// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
​
​
using IdentityServer4.Models;
using System.Collections.Generic;
​
namespace IdentityServer
{
    public static class Config
    {
        public static IEnumerable<IdentityResource> Ids =>
            new IdentityResource[]
            { 
                new IdentityResources.OpenId()
            };
​
        public static IEnumerable<ApiResource> Apis =>
            new ApiResource[] 
            { };
        
        public static IEnumerable<Client> Clients =>
            new Client[] 
            { };
        
    }
}

在 Configure() 中,則啟用了 IdentityServer 服務。

app.UseIdentityServer();

完整的代碼如下所示:

// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
​
​
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
​
namespace IdentityServer
{
    public class Startup
    {
        public IWebHostEnvironment Environment { get; }
​
        public Startup(IWebHostEnvironment environment)
        {
            Environment = environment;
        }
​
        public void ConfigureServices(IServiceCollection services)
        {
            // uncomment, if you want to add an MVC-based UI
            //services.AddControllersWithViews();
var builder = services.AddIdentityServer()
                .AddInMemoryIdentityResources(Config.Ids)
                .AddInMemoryApiResources(Config.Apis)
                .AddInMemoryClients(Config.Clients);
​
            // not recommended for production - you need to store your key material somewhere secure
            builder.AddDeveloperSigningCredential();
        }
​
        public void Configure(IApplicationBuilder app)
        {
            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
​
            // uncomment if you want to add MVC
            //app.UseStaticFiles();
            //app.UseRouting();
​
            app.UseIdentityServer();
​
            // uncomment, if you want to add MVC
            //app.UseAuthorization();
            //app.UseEndpoints(endpoints =>
            //{
            //    endpoints.MapDefaultControllerRoute();
            //});
        }
    }
}

 

參考資料

 

 


免責聲明!

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



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