zoukankan      html  css  js  c++  java
  • 第9章 使用客户端凭据保护API

    快速入门介绍了使用IdentityServer保护API的最基本方案。 我们将定义一个API和一个想要访问它的客户端。 客户端将通过提供ClientCredentials在IdentityServer请求访问令牌,ClientCredentials充当客户端和IdentityServer都知道的秘密,并且它将使用该令牌来访问API。

    9.1设置ASP.NET核心应用程序

    首先为应用程序创建一个目录 - 然后使用我们的模板创建一个包含基本IdentityServer设置的ASP.NET Core应用程序,例如:

    md quickstart
    cd quickstart
    
    md src
    cd src
    
    dotnet new is4empty -n IdentityServer
    

    这将创建以下文件:

    • IdentityServer.csproj- 项目文件和PropertieslaunchSettings.json文件
    • Program.csStartup.cs- 主要的应用程序入口点
    • Config.cs - IdentityServer资源和客户端配置文件

    您现在可以使用自己喜欢的文本编辑器来编辑或查看文件。如果您希望获得Visual Studio支持,可以添加如下解决方案文件:

    cd ..
    dotnet new sln -n Quickstart
    

    然后让它添加你的IdentityServer项目(记住这个命令,因为我们将在下面创建其他项目):

    dotnet sln add .srcIdentityServerIdentityServer.csproj
    

    注意
    此模板中使用的协议是http,当在Kestrel上运行时,端口设置为5000IISExpress上的随机端口。您可以在PropertieslaunchSettings.json文件中更改它。但是,所有快速入门指令都假定您使用Kestrel上的默认端口以及http协议,该协议足以进行本地开发。

    9.2 定义API资源

    API是您要保护的系统中的资源。

    资源定义可以通过多种方式加载,模板使用“代码作为配置”appproach。在Config.cs文件中,您可以找到一个名为GetApisAPI 的方法,如下所示:

    public static IEnumerable<ApiResource> GetApis()
    {
        return new List<ApiResource>
        {
            new ApiResource("api1", "My API")
        };
    }
    

    9.3 定义客户端

    下一步是定义可以访问此API的客户端。

    对于此方案,客户端将不具有交互式用户,并将使用IdentityServer的所谓客户端密钥进行身份验证。将以下代码添加到Config.cs文件中:

    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())
                },
    
                // scopes that client has access to
                AllowedScopes = { "api1" }
            }
        };
    }
    

    9.4 配置IdentityServer

    Startup.cs加载资源和客户端定义 - 模板已经为您执行此操作:

    public void ConfigureServices(IServiceCollection services)
    {
        var builder = services.AddIdentityServer()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApis())
            .AddInMemoryClients(Config.GetClients());
    
        // rest omitted
    }
    

    就是这样 - 如果您运行服务器并浏览浏览器 http://localhost:5000/.well-known/openid-configuration,您应该会看到所谓的发现文档。客户端和API将使用它来下载必要的配置数据。

    首次启动时,IdentityServer将为您创建一个开发人员签名密钥,它是一个名为的文件tempkey.rsa。您不必将该文件检入源代码管理中,如果该文件不存在,将重新创建该文件。

    9.5 添加API

    接下来,为您的解决方案添加API。

    您可以使用Visual Studio中的ASP.NET Core Web API(或空)模板,也可以使用.NET CLI来创建API项目。从src文件夹中运行以下命令:

    dotnet new web -n Api
    

    然后通过运行以下命令将其添加到解决方案中:

    cd ..
    dotnet sln add .srcApiApi.csproj
    

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

    "applicationUrl": "http://localhost:5001"
    

    9.6 控制器

    在API项目中添加一个新文件夹Controllers和一个新控制器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的眼睛(浏览工具)来可视化身份信息。

    9.7 配置

    最后一步是将身份验证服务添加到DI和身份验证中间件到管道。这些将:

    • 验证输入的令牌以确保它来自可信任的发布者(IdentityServer)
    • 验证令牌是否可用于该 api(也就是 Scope)。

    Startup更新为如下所示:

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();
    
            services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;
    
                    options.Audience = "api1";
                });
        }
    
        public void Configure(IApplicationBuilder app)
        {
            app.UseAuthentication();
    
            app.UseMvc();
        }
    }
    

    AddAuthentication将身份验证服务添加到DI并配置"Bearer"为默认方案。 UseAuthentication将身份验证中间件添加到管道中,以便在每次调用主机时自动执行身份验证。

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

    9.8 创建客户端

    最后一步是编写请求访问令牌的客户端,然后使用此令牌访问API。为此,在您的解决方案中添加一个控制台项目,请记住在以下位置创建它src:

    dotnet new console -n Client
    

    然后和以前一样,使用以下方法将其添加到您的解

    cd ..
    dotnet sln add .srcClientClient.csproj
    

    打开Program.cs并将内容从这里复制到它。

    客户端程序异步调用Main方法以运行异步http调用。 从C#7.1开始,此功能可用,一旦您编辑Client.csproj以将以下行添加为PropertyGroup,它就可用:

    <LangVersion>latest</LangVersion>
    

    IdentityServer的令牌端点实现OAuth 2.0协议,您可以使用原始HTTP来访问它。但是,我们有一个名为IdentityModel的客户端库,它将协议交互封装在易于使用的API中。

    IdentityModel NuGet包添加到您的客户端。这可以通过Visual Studio的nuget对话框,手动添加到Client.csproj文件,或使用CLI来完成:

    dotnet add package IdentityModel
    

    IdentityModel包括用于发现端点的客户端库。这样您只需要知道IdentityServer的基地址 - 可以从元数据中读取实际的端点地址:

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

    接下来,您可以使用发现文档中的信息向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);
    

    注意
    将访问令牌从控制台复制并粘贴到https://jwt.io/以检查原始令牌。

    9.9 调用

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

    // call api
    var client = new HttpClient();
    client.SetBearerToken(tokenResponse.AccessToken);
    
    var response = await client.GetAsync("http://localhost:5001/identity");
    if (!response.IsSuccessStatusCode)
    {
        Console.WriteLine(response.StatusCode);
    }
    else
    {
        var content = await response.Content.ReadAsStringAsync();
        Console.WriteLine(JArray.Parse(content));
    }
    

    输出应如下所示:

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

    9.10 进一步的实验

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

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

    你现在可以尝试引发一些错误来学习系统的相关行为,比如:

    • 尝试在未运行时连接到IdentityServer(不可用)
    • 尝试使用无效的客户端ID或密码来请求令牌
    • 尝试在令牌请求期间请求无效范围
    • 尝试在API未运行时调用API(不可用)
    • 不要将令牌发送到API
    • 将API配置为需要与令牌中的范围不同的范围

    github地址

  • 相关阅读:
    84. Largest Rectangle in Histogram (Solution 2)
    84. Largest Rectangle in Histogram (Solution 1)
    73. Set Matrix Zeroes
    【JavaScript】Symbol 静态方法
    【JavaScript】Date
    【JavaScript】Math
    725. Split Linked List in Parts把链表分成长度不超过1的若干部分
    791. Custom Sort String字符串保持字母一样,位置可以变
    508. Most Frequent Subtree Sum 最频繁的子树和
    762. Prime Number of Set Bits in Binary Representation二进制中有质数个1的数量
  • 原文地址:https://www.cnblogs.com/thinksjay/p/10774718.html
Copyright © 2011-2022 走看看