通过OpenIddict设计一个授权服务器03-客户凭证流程

在本部分中,我们将把 OpenIddict 添加到项目中,并实施第一个授权流程:客户端凭证流。

添加 OpenIddict 软件包

首先,我们需要安装 OpenIddict NuGet 软件包

dotnet add package OpenIddict
dotnet add package OpenIddict.AspNetCore
dotnet add package OpenIddict.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.InMemory

在这里插入图片描述
除了主库,我们还安装了 OpenIddict.AspNetCore 软件包,该软件包可将 OpenIddict 集成到 ASPNET Core 主机中。
OpenIddict.EntityFrameworkCore 包支持 Entity Framework Core。现在我们将使用内存实现,为此我们使用了 Microsoft.EntityFrameworkCore.InMemory. 包。

设置 OpenIddict

我们将首先介绍启动和运行 OpenIddict 所需的最低条件。必须启用至少一个 OAuth 2.0/OpenID Connect 流程。我们选择启用客户端凭证流,它适用于机器到机器应用程序。在本系列的下一部分,我们将使用 PKCE 实现授权代码流,这是单页应用程序 (SPA) 和本地/移动应用程序的推荐流程。
开始对 Startup.cs 进行以下更改:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>{options.LoginPath = "/account/login";});
builder.Services.AddDbContext<DbContext>(options =>
{// 使用内存存储options.UseInMemoryDatabase(nameof(DbContext));// 注册OpenIddict所需的实体集。options.UseOpenIddict();
});
builder.Services.AddOpenIddict()// 注册 OpenIddict 核心组件.AddCore(options =>{// 配置 OpenIddict 以使用 EF Core 存储器/模型options.UseEntityFrameworkCore().UseDbContext<DbContext>();})// 注册 OpenIddict 服务器组件.AddServer(options =>{options.AllowClientCredentialsFlow();options.SetTokenEndpointUris("/connect/token");//令牌的加密和签名options.AddEphemeralEncryptionKey().AddEphemeralSigningKey();//注册范围(权限)options.RegisterScopes("api");//注册 ASP.NET Core 主机并配置 ASP.NET Core 特定选项 options.UseAspNetCore().EnableTokenEndpointPassthrough();});var app = builder.Build();app.UseStaticFiles();app.UseRouting();
app.UseAuthentication();
app.MapDefaultControllerRoute();
app.Run();

首先,在 ConfigureServices 方法中注册 DbContext。OpenIddict 原生支持 Entity Framework Core、Entity Framework 6 和 MongoDB,你也可以提供自己的存储。
在本例中,我们将使用 Entity Framework Core,并使用内存数据库。options.UseOpenIdDict 调用会注册 OpenIddict 所需的实体集。

接下来是注册 OpenIddict 本身。AddOpenIddict() 调用会注册 OpenIddict 服务,并返回一个 OpenIddictBuilder 类,我们可以用它来配置 OpenIddict。

首先注册的是核心组件。OpenIddict 被指示使用 Entity Framework Core,并使用前面提到的 DbContext。
接下来,注册服务器组件并启用客户端凭证流。为使该流程正常运行,我们需要注册一个令牌端点。我们需要自己实现这个端点。我们稍后再做这项工作。

要使 OpenIddict 能够加密和签名令牌,我们需要注册两个密钥,一个用于加密,一个用于签名。在本例中,我们将使用短暂密钥。短暂密钥会在应用程序关闭时自动丢弃,因此使用这些密钥签名或加密的有效负载会自动失效。这种方法只能在开发过程中使用。在生产过程中,建议使用 X.509 证书。

RegisterScopes 定义了支持哪些作用域(权限)。在本例中,我们只有一个名为 api 的作用域,但授权服务器可以支持多个作用域
UseAspNetCore() 调用用于将 AspNetCore 设置为 OpenIddict 的主机。我们还调用了 EnableTokenEndpointPassthrough,否则会阻止对未来令牌端点的请求。
要检查 OpenIddict 是否配置正确,我们可以启动应用程序并导航到:https://localhost:5001/.well-known/openid-configuration,得到的回应应该是这样的:

{"issuer": "https://localhost:5001/","token_endpoint": "https://localhost:5001/connect/token","jwks_uri": "https://localhost:5001/.well-known/jwks","grant_types_supported": ["client_credentials"],"scopes_supported": ["openid","api"],"claims_supported": ["aud","exp","iat","iss","sub"],"id_token_signing_alg_values_supported": ["RS256"],"subject_types_supported": ["public"],"token_endpoint_auth_methods_supported": ["client_secret_post","private_key_jwt","client_secret_basic"],"claims_parameter_supported": false,"request_parameter_supported": false,"request_uri_parameter_supported": false,"authorization_response_iss_parameter_supported": true
}

在这里插入图片描述
在本指南中,我们将使用 Postman 测试授权服务器,但也可以使用其他工具。
下面是一个使用 Postman 的授权请求示例。授权类型是客户凭据流。我们指定了访问令牌 url、客户端 ID 和秘密,以验证客户端身份。我们还请求访问 api 范围。
直接请求https://localhost:5001/connect/token
在这里插入图片描述

如果我们请求令牌,操作将失败:client_id 无效。这是有道理的,因为我们还没有在授权服务器上注册任何客户端。
发送post请求
在这里插入图片描述
用代码实现

using Flurl.Http;namespace AuthClient
{internal class Program{static void Main(string[] args){var dic = new Dictionary<string, string>();dic.Add("grant_type", "client_credentials");dic.Add("client_id","postman");dic.Add("client_secret", "postman-secret");dic.Add("scope", "api");string url = "https://localhost:5001/connect/token";var response = url.PostUrlEncodedAsync(dic).Result;Console.WriteLine(response.ResponseMessage.Content.ReadAsStringAsync().Result);Console.WriteLine("完成");}}
}

我们可以通过将客户端添加到数据库来创建客户端。为此,我们创建了一个名为 TestData 的类。测试数据实现了 IHostedService 接口,这使我们能够在应用程序启动时在 Startup.cs 中执行生成测试数据的操作。

using Microsoft.EntityFrameworkCore;
using OpenIddict.Abstractions;namespace AuthorizationServer
{public class TestData : IHostedService{private readonly IServiceProvider _serviceProvider;public TestData(IServiceProvider serviceProvider){_serviceProvider = serviceProvider;}public async Task StartAsync(CancellationToken cancellationToken){using var scope = _serviceProvider.CreateScope();var context = scope.ServiceProvider.GetRequiredService<DbContext>();await context.Database.EnsureCreatedAsync(cancellationToken);var manager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();if (await manager.FindByClientIdAsync("postman", cancellationToken) is null){await manager.CreateAsync(new OpenIddictApplicationDescriptor{ClientId = "postman",ClientSecret = "postman-secret",DisplayName = "Postman",Permissions ={OpenIddictConstants.Permissions.Endpoints.Token,OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,OpenIddictConstants.Permissions.Prefixes.Scope + "api"}}, cancellationToken);}}public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;}
}

客户端在测试数据中注册。客户端 ID 和秘密用于客户端与授权服务器之间的身份验证。权限决定了客户端的选项。
在这种情况下,我们允许客户端使用客户端凭据流,访问令牌端点,并允许客户端请求 api 范围。
在 Startup.cs 中注册测试数据服务,以便在应用程序启动时执行:

builder.Services.AddHostedService<TestData>();

在这里插入图片描述
如果我们再次尝试用 Postman 获取访问令牌,请求仍然会失败。这是因为我们还没有创建令牌端点。我们现在就创建。
在这里插入图片描述

创建一个名为 AuthorizationController 的新控制器,我们将在此托管端点:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Mvc;
using OpenIddict.Abstractions;
using OpenIddict.Server.AspNetCore;
using System.Security.Claims;namespace AuthorizationServer.Controllers
{public class AuthorizationController : Controller{[HttpPost("~/connect/token")]public IActionResult Exchange(){var request = HttpContext.GetOpenIddictServerRequest() ??throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");ClaimsPrincipal claimsPrincipal;if (request.IsClientCredentialsGrantType()){// 注意:OpenIddict 会自动验证客户端凭证:// 如果 client_id 或 client_secret 无效,则不会调用此操作。var identity = new ClaimsIdentity(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);// Subject (sub)是必填字段,我们在此使用客户 ID 作为主题标识符。identity.AddClaim(OpenIddictConstants.Claims.Subject, request.ClientId ?? throw new InvalidOperationException());// 添加一些要求,别忘了添加目的地,否则它不会被添加到访问令牌中。identity.AddClaim("some-claim", "some-value", OpenIddictConstants.Destinations.AccessToken);//上面这句话不起作用,下面的可以identity.AddClaim(new Claim("some-claim2", "some-value2").SetDestinations(OpenIddictConstants.Destinations.AccessToken));claimsPrincipal = new ClaimsPrincipal(identity);claimsPrincipal.SetScopes(request.GetScopes());}else{throw new InvalidOperationException("The specified grant type is not supported.");}// 返回 SignInResult 结果时,OpenIddict 将向用户发放相应的访问/身份令牌。return SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);}}
}

其中一个操作是 “Exchange”。所有流程(不仅是客户证书流程)都使用该操作来获取访问令牌。

在客户凭据流中,令牌是根据客户凭据签发的。而在授权码流中,使用的是同一个端点,但随后会用授权码来交换令牌。我们将在第四部分看到这一点。

目前,我们需要重点关注客户端凭证流程。当请求进入 Exchange 操作时,客户端凭证(ClientId 和 ClientSecret)已经通过 OpenIddict 验证。因此,我们不需要对请求进行验证,只需创建一个声称委托人并使用该委托人登录即可。

声明主体与账户控制器中使用的声明不同,后者基于 Cookie 身份验证处理程序,仅在授权服务器本身的上下文中使用,以确定用户是否已通过身份验证。

我们必须创建基于 OpenIddictServerAspNetCoreDefaults.AuthenticationScheme 的请求声明。这样,当我们在该方法末尾调用 SignIn 时,OpenIddict 中间件就会处理登录并返回一个访问令牌作为对客户端的响应。

只有当我们指定目的地时,才会在访问令牌中加入权利要求声明中定义的权利要求。示例中的 "some-value "请求将被添加到访问令牌中。
主题(Subject)要求是必填项,您无需指定目的地,因为它将包含在访问令牌中。

我们还通过调用 claimsPrincipal.SetScopes(request.GetScopes()); 授权所有请求的作用域。OpenIddict 已经检查了所请求的作用域是否被允许(一般情况下和针对当前客户端)。我们之所以要在此处手动添加作用域,是因为我们可以根据需要过滤此处授予的作用域。

一枚令牌定乾坤

让我们再次尝试用 Postman 获取访问令牌,这次应该能成功。
在这里插入图片描述
从 OpenIddict v3 开始,访问令牌默认采用 Jason Web Token(JWT)格式。这使我们能够使用 jwt.io 检查令牌(感谢 Auth0 提供的服务!)。
一个问题是,令牌不仅要签名,还要加密。OpenIddict 默认会对访问令牌进行加密。我们可以在 Startup.cs 中配置 OpenIddict 时禁用这种加密。
在这里插入图片描述
现在,当我们重启授权服务器并请求一个新的令牌时。将令牌粘贴到 jwt.io 并查看令牌内容:
在这里插入图片描述

可以看到,客户 ID postman 被设置为Subject(sub)。此外,访问令牌中还添加了 some-claim claim。

接下来干什么

恭喜您,您已经使用 OpenIddict 实现了客户端凭证流!
您可能已经注意到,客户端凭证流未使用登录页面。该流程会立即将客户端凭据交换为令牌,适用于机器对机器应用程序。
接下来,我们将使用 PKCE 实现授权代码流,这是单页应用程序(SPA)和移动应用程序的推荐流程。该流程将涉及用户,因此我们的登录页面将发挥作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/631505.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp+vue3打包问题记录

**背景&#xff1a;**打包app出现问题&#xff0c;只显示底部导航的文字&#xff0c;其他一片空白 1. pages.json文件&#xff1a;tabBar中的iconPath图标格式不支持svg&#xff0c;只支持&#xff1a;png, jpg, jpeg的格式&#xff0c;当图片改为.png的时候可以正常显示 2. …

【数学建模】2024年华数杯国际赛B题-光伏发电Photovoltaic Power 思路、代码、参考论文

1 问题背景 中国电力构成包括传统能源(如煤炭、石油、天然气)、可再生能源(如水电、风能、太阳能、核能)和其他形式的电力。这些发电模式在满足中国巨大的电力需求方面发挥着至关重要的作用。据最新数据显示&#xff0c;中国总发电量超过20万亿千瓦时&#xff0c;居世界第一。…

idea社区版 MybatisCodeHelperPro插件使用介绍

文章目录 一、插件介绍二、idea社区版安装MybatisCodeHelperPro插件三、问题记录1. DatabaseHelper插件 加载不了部分数据库链接的列信息2. DatabaseHelper插件 数据库列显示顺序错乱3. MybatisCodeHelperPro插件 数据库字段不提示4. MybatisCodeHelperPro插件 特殊字段增加反引…

Skywalking链路追踪

目录 一、简介1.1、APM系统1.2、SkyWalking 简介 二、快速入门2.1、下载、启动2.2、界面认识 三、持久化存储四、告警通知五、自定义追踪-细粒度追踪service方法 一、简介 1.1、APM系统 APM&#xff08;Application Performance Monitoring&#xff09;系统是一种用于监控和管…

VR风景园林虚拟仿真系统编辑工具支持可视化预览成本低

为了帮助更多人快速、高效地构建虚拟现实应用系统&#xff0c;提高开发效率&#xff0c;降低成本投入&#xff0c;VR虚拟现实交互系统编辑器作为一种用于创建和编辑虚拟现实应用程序的工具&#xff0c;采用可视化界面提示和简单操作就能快速制作VR虚拟现实交互系统。 VR虚拟现实…

使用jackson对java类中包含泛型属性的bean进行序列化和反序列化

最近在做项目时&#xff0c;需要对java的bean对象进行序列化转换为string字符串后&#xff0c;存入redis&#xff0c;然后再从redis中读取该string对象&#xff0c;反序列化为bean对象。正常的简单类型的对象使用jackson可以非常方便进行互为转换操作&#xff0c;但我们操作的对…

Qt OpenGL - 网格式的直角坐标系

Qt OpenGL - 网格式的直角坐标系 引言一、绘制3D网格1.1 绘制平行于y轴的线段1.2 绘制平行于三个轴的线段1.3 绘制不同的3D网格 二、网格式的直角坐标系三、参考链接 引言 在OpenGL进行3D可视化&#xff0c;只绘制三条坐标轴略显单薄&#xff0c;而绘制网格形式的坐标系则能更清…

leedcode刷题笔记day1

题目大意&#xff1a; 暴力解法 两个for循环&#xff08;也是我一看到题目想到的方法&#xff09; 枚举在数组中所有的不同的两个下标的组合逐个检查它们所对应的数的和是否等于 target 复杂度分析 时间复杂度:O(n2)&#xff0c;这里 n 为数组的长度 空间复杂度:O(1)&#x…

canvas绘制不同样式的五角星(图文示例)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

Windows无法格式化U盘怎么办?

U盘通常用于保存数据。有时&#xff0c;您可能需要格式化以擦除硬盘或修复错误等。通常&#xff0c;格式化过程可以通过Windows文件资源管理器、磁盘管理或Diskpart命令顺利进行&#xff0c;但有时会遇到Windows无法格式化U盘的情况。那么&#xff0c;Windows无法格式化U盘怎么…

uni-app的数据缓存

数据缓存uni.setStorage 将数据存储在本地缓存中指定的 key 中&#xff0c;会覆盖掉原来该 key 对应的内容&#xff0c;这是一个异步接口。 参数名类型必填说明keyString是本地缓存中的指定的 keydataAny是需要存储的内容&#xff0c;只支持原生类型、及能够通过 JSON.string…

程序员第一次接私活需要注意什么?

终于有一篇只说大白话的程序员接私活指南文章了&#xff01;程序员接私活&#xff0c;首先要关注合法和合理性 先来说合法性&#xff0c;这是程序员接私活的基本原则。不合规的产品不要做&#xff0c;不合法的需求不要做&#xff0c;原以为自己在赚钱&#xff0c;结果搞了半天啥…

1.2 虚拟环境

1.2 虚拟环境 创建好应用目录之后&#xff0c;接下来该安装Flask了。安装Flask最便捷的方法是使用虚拟环境。 虚拟环境是Python解释器的一个私有副本&#xff0c;在这个环境中你可以安装私有包&#xff0c;而且不会影响系统中安装的全局Python解释器。 虚拟环境非常有用&…

Docker registry镜像仓库,私有仓库及harbor管理详解

目录 registry镜像仓库概述 Docker 镜像仓库&#xff08;Docker Registry&#xff09;&#xff1a; registry 容器&#xff1a; 私有仓库概述 搭建本地私有仓库示例 Harbor概述 harbor架构 详解构成 Harbor由容器构成 Harbor部署示例 环境准备 部署Docker-Compose服…

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (4) | 神经网络与反向传播

前言 &#x1f4da; 笔记专栏&#xff1a;斯坦福CS231N&#xff1a;面向视觉识别的卷积神经网络&#xff08;23&#xff09;&#x1f517; 课程链接&#xff1a;https://www.bilibili.com/video/BV1xV411R7i5&#x1f4bb; CS231n: 深度学习计算机视觉&#xff08;2017&#xf…

1月18日代码随想录二叉树搜索、验证二叉搜索树

700.二叉搜索树中的搜索 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和一个整数值 val。 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 null 。 示例 1: 输入&#xff1a;root [4,2,7,1,3], val …

医院网络安全建设:三网整体设计和云数据中心架构设计

医院网络安全问题涉及到医院日常管理多个方面&#xff0c;一旦医院信息管理系统在正常运行过程中受到外部恶意攻击&#xff0c;或者出现意外中断等情况&#xff0c;都会造成海量医疗数据信息的丢失。由于医院信息管理系统中存储了大量患者个人信息和治疗方案信息等&#xff0c;…

【ArcGIS微课1000例】0088:计算城市建筑物朝向(矩形角度)

文章目录 一、实验描述二、实验数据三、角度计算1. 添加字段2. 计算角度四、方向计算一、实验描述 矩形要素具有长轴和短轴,其长轴方向也称为矩形面的主角度,可用于确定面要素的走向趋势。根据该方向参数,可以对具有矩形特征的地理对象进行方向分析,且适用于很多应用场景,…

什么是NodeJS

1、前言 接触 node.js 有好几年了&#xff0c;也开发了好几个项目了&#xff1b;但每次提起 node.js&#xff0c;始终不敢说自己入门了&#xff0c;归其原因&#xff0c;大概就是如下所示 为了进一步加强理解&#xff0c;系统的梳理相关知识以作备忘&#xff0c;本节将从以下…

视频转码实例:把MP4转为MKV视频,一键批量转换的操作方法

在数字媒体时代&#xff0c;视频格式的多样性是不可避免的。经常把MP4格式的视频转换为MKV格式。MKV格式有较高的音频和视频质量&#xff0c;能在其他设备或软件上播放视频。以下是云炫AI智剪如何把MP4视频转为MKV格式的一键批量转换操作方法。 已转码的mkv视频效果缩略图展示…