IdentityServer4_1.ClientCredentials

Identityserver4

Client Credentials

image-20211112135956446

客户端凭证模式

1.准备

dotnet CLI快速安装模板Identityserver模板

dotnet new -i IdentityServer4.Templates

2.创建Asp .net core应用程序

创建IdentityServery 项目

md quickstart
cd quickstart

md src
cd src

dotnet new is4empty -n IdentityServer

这将创建以下文件:

  • IdentityServer.csproj- 项目文件和一个Properties\launchSettings.json文件
  • Program.csStartup.cs- 主应用程序入口点
  • Config.cs - IdentityServer 资源和客户端配置文件

创建Quickstart一个解决方案,更好的获得visual studio的支持

PS D:\quickstart\src> cd ..
PS D:\quickstart> dotnet new sln -n Quickstart
The template "Solution File" was created successfully.

把 IdentityServer 项目添加到解决方案中

dotnet sln add .\src\IdentityServer\IdentityServer.csproj

笔记

此模板中使用的协议是https,在 Kestrel 上运行时端口设置为 5001 或在 IISExpress 上运行时设置为随机端口。您可以在Properties\launchSettings.json文件中更改它。对于生产场景,您应该始终使用https.

Defining an API Scope

API 是系统中要保护的资源。资源定义可以通过多种方式加载,您用于创建上述项目的模板显示了如何使用“代码即配置”方法。

已经为您创建了 Config.cs。打开它,将代码更新为如下所示:

public static class Config
{
    ///定义API范围
    public static IEnumerable<ApiScope> ApiScopes =>
        new List<ApiScope>
    {
        new ApiScope("api1", "My API")
    };
}

Defining the client

///定义客户端
public static IEnumerable<Client> Clients =>
    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())///应用程序密码
        },

        // scopes that client has access to
        AllowedScopes = { "api1" }
    }
};

配置身份服务器

加载资源和客户端定义发生在[Startup.cs 中]


public void ConfigureServices(IServiceCollection services)
{
    var builder = services.AddIdentityServer()
        .AddDeveloperSigningCredential()        //This is for dev only scenarios when you don’t have a certificate to use.
        .AddInMemoryApiScopes(Config.ApiScopes)
        .AddInMemoryClients(Config.Clients);

    // omitted for brevity
}

测试

浏览器测试

如果您运行服务器并将浏览器导航到https://localhost:5001/.well-known/openid-configuration,您应该会看到所谓的发现文档。发现文档是身份服务器中的标准端点。您的客户端和 API 将使用发现文档来下载必要的配置数据。

image-20211109112525391

通过Postman调用

image-20211109151557448

3.创建WebAPI

向解决方案中添加API

src文件夹下运行一下命令

dotnet new webapi -n Api

将其添加到解决方案中

cd ..
dotnet sln add .\src\Api\Api.csproj

将 API 应用程序配置为https://localhost:6001仅在其上运行。您可以通过编辑Properties 文件夹中的launchSettings.json文件来执行此操作。将应用程序 URL 设置更改为:

"applicationUrl": "https://localhost:6001"

控制器

添加一个名为 的新类IdentityController

[Route("identity")]
[Authorize]
public class IdentityController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
    }
}

此控制器稍后将用于测试授权要求,以及通过 API 的眼睛可视化声明身份。

添加 Nuget 依赖项

为了使配置步骤工作,必须添加 nuget 包依赖项,请在根目录中运行以下命令:

dotnet add .\\src\\api\\Api.csproj package Microsoft.AspNetCore.Authentication.JwtBearer

因为包与项目框架不兼容,执行会报错。需要选定Microsoft.AspNetCore.Authentication.JwtBearer的对应版本

image-20211109135559490

配置

最后一步是将身份验证服务添加到 DI(依赖注入)并将身份验证中间件添加到管道中。这些将:

  • 验证传入的令牌以确保它来自受信任的发行者
  • 验证令牌是否有效与此 API 一起使用(又名受众)

将启动更新为如下所示:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        services.AddAuthentication("Bearer")
            .AddJwtBearer("Bearer", options =>
                          {
                              options.Authority = "https://localhost:5001";

                              options.TokenValidationParameters = new TokenValidationParameters
                              {
                                  ValidateAudience = false
                              };
                          });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
                         {
                             endpoints.MapControllers();
                         });
    }
}
  • AddAuthentication将身份验证服务添加到 DI 并配置Bearer为默认方案。
  • UseAuthentication 将身份验证中间件添加到管道中,因此每次调用主机时都会自动执行身份验证。
  • UseAuthorization 添加授权中间件以确保匿名客户端无法访问我们的 API 端点。

https://localhost:6001/identity在浏览器上导航到控制器应返回 401 状态代码。这意味着您的 API 需要凭证并且现在受 IdentityServer 保护。

4.Creating the client

src目录下创建client

dotnet new console -n Client

添加到您的解决方案

cd ..
dotnet sln add .\src\Client\Client.csproj

Add the IdentityModel NuGet package to your client.

cd src
cd client
dotnet add package IdentityModel

IdentityModel 包括一个与发现端点一起使用的客户端库

在main方法中添加如下内容

// discover endpoints from metadata
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

如果您在连接时遇到错误,则可能是您正在运行https并且其开发证书localhost不受信任。您可以运行以信任开发证书。这只需要做一次。dotnet dev-certs https --trust

接下来,您可以使用发现文档中的信息向 IdentityServer 请求令牌以访问api1

// request token
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
                                                                    {
                                                                        Address = disco.TokenEndpoint,

                                                                        ClientId = "client",
                                                                        ClientSecret = "secret",
                                                                        Scope = "api1"
                                                                    });

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);

将访问令牌从控制台复制并粘贴到jwt.ms以检查原始令牌。

控制台输出[jwt.ms]

QsImV4cCI6MTYzNjQ0MjkyNCwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NTAwMSIsImNsaWVudF9pZCI6ImNsaWVudCIsImp0aSI6IkY5ODEyOTZDODczMTkyOEJERkUyMTlEMzlFODRDMEQxIiwiaWF0IjoxNjM2NDM5MzI0LCJzY29wZSI6WyJhcGkxIl19.AF00jjPL1lrdftbJhfQNKmULL9-0lUyHh3os1KRDusp7s4PA_fvJ5VnIoPohQM266NCXHxKTMs5jXIQWRcyk95zv5iKhufBStqyH3IuG5NHF658bmQDBoVI06_KMNnQERoNmzlNcMERU0-ekyxQefPjKWLoUs7Vn3daJS22PYqz5L9PY5SxM69rQtijEJIZO9MeGxChu6suVZe0JDtn4960J9IbFwG1eOpbqxwdIpKVXDTPV8II29BL8qGk_Us_1AMThJIoUMj96V9CnN7u6uK_SUsQalXz9xEPdsTy3lbix5-uajpGIXYxNAfmSu7wysm487yztruNtshhL133JkQ","expires_in":3600,"token_type":"Bearer","scope":"api1"}

调用 API

要将访问令牌发送到 API,您通常使用 HTTP 授权标头。这是使用SetBearerToken扩展方法完成的:

// call api
var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);

var response = await apiClient.GetAsync("https://localhost:6001/identity");
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var content = await response.Content.ReadAsStringAsync();
    Console.WriteLine(JArray.Parse(content));
}

运行以后,输出:

image-20211109143329081

默认情况下,访问令牌将包含有关范围、生命周期(nbf 和 exp)、客户端 ID (client_id) 和颁发者名称 (iss) 的声明。

API 授权

现在,API 接受您的身份服务器颁发的任何访问令牌。

在下文中,我们将添加允许检查范围是否存在于客户端请求(并被授予)的访问令牌中的代码。为此,我们将使用 ASP.NET Core 授权策略系统。将以下内容添加到StartupConfigureServices方法中:

services.AddAuthorization(options =>
                          {
                              options.AddPolicy("ApiScope", policy =>
                                                {
                                                    policy.RequireAuthenticatedUser();
                                                    policy.RequireClaim("scope", "api1");
                                                });
                          });

您现在可以在各个级别执行此策略,例如

  • 全球
  • 对于所有 API 端点
  • 对于特定的控制器/动作

通常,您为路由系统中的所有 API 端点设置策略:

app.UseEndpoints(endpoints =>
                 {
                     endpoints.MapControllers()
                         .RequireAuthorization("ApiScope");
                 });
dotnet run --project D:\project\IdentityServerSampleNew\quickstart\1_ClientCredentials\src\IdentityServer\IdentityServer.csproj  #Now listening on: https://localhost:5001
dotnet run --project D:\project\IdentityServerSampleNew\quickstart\1_ClientCredentials\src\Api\api.csproj #Now listening on: https://localhost:65002
dotnet run --project D:\project\IdentityServerSampleNew\quickstart\1_ClientCredentials\src\Client\Client.csproj

进一步的实验

本演练重点介绍了迄今为止的成功路径

  • 客户端能够请求令牌
  • 客户端可以使用令牌访问 API

您现在可以尝试引发错误以了解系统的行为方式,例如

  • 尝试在 IdentityServer 未运行时连接到它(不可用)

    image-20211110104451063

  • 尝试使用无效的客户端 ID 或机密来请求令牌

    服务端信息

    image-20211110104335594

    客户端返回信息

    image-20211110104219706

  • 尝试在令牌请求期间请求无效范围

    服务器:

    image-20211110105104491

    客户端

    image-20211110104911505

  • 尝试在未运行时调用 API(不可用)

image-20211110105312278

  • 不要将令牌发送到 API

image-20211110105453943

  • 将 API 配置为需要与令牌中的范围不同的范围

image-20211110105854130

  • 将令牌中的范围设置为与API不同的范围

image-20211110111338461

参考资料

Identityserver4官方文档

参考源码
password

posted @ 2021-11-09 15:30  CCmonitor  阅读(103)  评论(0编辑  收藏  举报