带有GraphQL数据访问和JWT身份验证的.NET 5服务
目录
介绍
服务如何运作?
GraphQL的用法和优化
组成和结构
如何运行?
前提条件(对于Windows)
行动顺序
使用Playground的查询和变异
测验
结论
本文和代码说明了.NET 5中GraphQL的用法。GraphQL数据访问已通过数据缓存进行了优化。开发了一些库来支持GraphQL、JWT身份验证、TLS、可配置日志记录。
- 下载源代码242.9 KB
介绍
本文介绍了两个.NET 5 Web服务。第一个GraphQlService支持使用GraphQL技术通过数据库(SQL Server)创建、检索、更新和删除(CRUD)操作。传输层安全性(TLS)保护消息在跨网络传输时不被读取,并且使用JSON Web令牌(JWT)进行用户身份验证和授权。第二种LoginService提供用户登录机制,并根据用户的凭证生成JWT。
维基:
GraphQL是一种用于API的开源数据查询和操作语言,并且是用于使用现有数据执行查询的运行时。GraphQL由Facebook在2012年内部开发,并于2015年公开发布。目前,GraphQL项目由GraphQL Foundation运行。它提供了一种开发Web API的方法,并且已与REST和其他Web服务体系结构进行了比较和对比。它允许客户端定义所需数据的结构,并从服务器返回相同的数据结构,因此可以防止返回过多的数据。
本文的代码演示了以下主要功能:
- 使用GraphQL技术的交易数据存储库的CRUD操作
- 方便的Playground和GraphiQL现成的Web UI应用程序,用于GraphQL查询和变异,不需要前端代码
- JWT认证
- OpenApi(又名Swagger)与GraphQL结合使用
- 灵活的可配置日志记录(当前已配置为仅向控制台提供一些最小输出)
- 使用内存服务进行集成测试
使用了几个使用NuGet进行GraphQL开发的开源软件包。
服务如何运作?
服务的工作如下图所示:
图1.服务工作
要开始她/他的工作,用户需要向LoginService (1)提供凭据(用户名和密码)。后者生成JWT并将其返回给用户。然后,用户向GraphQlService (2) 发送查询/更新,并从服务获得响应。
这些服务具有单独的数据库。LoginService访问的用户数据库包UsersDb含一个Users表,该表由用户名、密码(在现实世界中加密)和每个用户的角色组成。GraphQlService访问的人员数据库PersonsDb包含几个与人员、组织及其关系和隶属关系有关的表。
GraphQL的用法和优化
GraphQL定义了客户端和服务器之间的约定,用于数据检索(查询)和更新(变异)。查询和变异都构成类似JSON的结构。检索到的数据被格式化为与请求几乎相同的结构,然后返回给客户端。由于GraphQL查询的分层形式,数据检索的过程是对嵌套字段的处理程序的一系列调用。
GraphQL暗示对每个数据字段使用解析函数(解析器)。通常,包括此处使用的GraphQL的实现可确保在Web响应层次结构形成期间调用适当的解析器。如果每个解析器向数据库发出SELECT查询,则这些查询的总数等于层次结构每个级别上的返回行之和。考虑一个获取所有人的查询。在最高级别,所有n个人都被提取。然后在第二级,SELECT查询被执行Ñ是时候获取每个人的隶属关系。在以下每个级别上观察到相似的图片。显然,大量的返回行导致对数据库的大量查询,从而导致严重的性能损失。在这种情况下,对数据库的查询数为:
此问题通常称为N + 1查询问题。
高效的GraphQL实现必须为该问题提供合理的解决方案。在这项工作中实现的解决方案可以表述如下。在“天真的”实现中,每个字段的处理程序都调用数据库来检索数据。在优化的解决方案中,每个级别上的字段处理程序的第一次调用都会从数据库数据中检索该级别上所有字段的信息,并将它们存储在附加到GraphQL上下文对象的缓存中。GraphQL上下文对象可用于所有字段处理程序。给定级别字段处理程序的后续调用从缓存而不是从数据库获取数据。在优化的情况下,对数据库的查询数为:
database_queries = levels
如您所见,数据库调用的数量(SELECT -s)与GraphQL查询的内部级别相对应,并且与每个级别上提取的记录的数量无关。
差异在下面的图2和图3中说明:
图2.未优化的数据提取
图3.优化的数据获取
解析程序的返回值将自动插入到GraphQL查询的响应对象中。我们仅需要提供该级别的解析器中已经从数据库中获取的数据的返回值。实现此目的的最简单方法是将获取的数据放入内存中的缓存对象,并将其附加到所有解析程序可用的上下文对象中。根据解析器,将缓存组织为具有关键字的字典。每个解析器都使用适当的密钥返回从缓存中提取的一条数据。
这些返回值形成响应对象,以完成GraphQL查询后发送回客户端。由于缓存对象是上下文对象的属性,因此在GraphQL查询处理结束时,它将与上下文一起销毁。因此,为每个客户端请求创建了缓存对象,并且缓存对象的生存期受到此请求处理的限制。
基于内存缓存的数据采集优化可提高性能。但是,它的限制在于可用操作内存(RAM)的大小。如果缓存对象太大而无法容纳在单个进程内存中,则可以使用分布式缓存解决方案,例如Redis,Memcached或类似的缓存。在本文中,我们假设简单的内存高速缓存可以满足绝大多数实际情况。
组成和结构
成分 |
项目类型 |
地点 |
描述 |
GraphQlService |
服务(控制台应用程序) |
.\ |
该服务使用GraphQL技术执行CRUD操作。它提供了两个控制器。GqlController处理所有的GraphQL请求,而PersonController处理无参数的GET请求和一些预定义的文本,以及另一个以Person id作为参数的GET请求。该请求在内部作为具有硬编码查询的普通GraphQL请求进行处理。它是常用GraphQL查询的“捷径”。在此,PersonController主要用于说明目的。 |
LoginService |
服务(控制台应用程序) |
.\ |
该服务支持用户登录过程。它具有一个LoginController创建JWT以响应用户的凭据。 |
ServicesTest |
测试项目(控制台应用程序) |
.\Tests |
Project为这两种服务都提供集成测试。这些测试基于内存服务的概念。这种方法使开发人员可以轻松测试实际的服务代码。 |
ConsoleClient |
控制台应用 |
.\ |
用于服务的简单客户端控制台应用程序。 |
PersonModelLib |
动态链接库 |
.\Model |
该项目提供了针对给定领域问题的特定代码(在我们的案例中是Persons)。 |
AsyncLockLib |
动态链接库 |
.\Libs |
提供异步/等待方法的锁定机制,特别适用于GraphQL缓存的实现。 |
AuthRolesLib |
动态链接库 |
.\Libs |
提供enum UserAuthRole。 |
GraphQlHelperLib |
动态链接库 |
.\Libs |
包含与GraphQL相关的常规代码,其中包括一个用于数据缓存的代码,用于解决N + 1个查询问题。 |
HttpClientLib |
动态链接库 |
.\Libs |
用于创建HTTP客户端,实现HttpClientWrapper类。 |
JwtAuthLib |
动态链接库 |
.\Libs |
通过用户的凭证生成JWT |
JwtLoginLib |
动态链接库 |
.\Libs |
提供用户登录处理,使用JwtAuthLib。 |
RepoInterfaceLib |
动态链接库 |
.\Libs |
定义IRepo<T>用于处理事务数据存储库的接口。 |
RepoLib |
动态链接库 |
.\Libs |
为EntityFrameworkCore实现RepoInterfacesLib中的IRepo<T>接口。它为数据保存程序配备了事务处理。 |
如何运行?
前提条件(对于Windows)
- 本地SQL Server(请参阅服务的文件appsettings.json中的连接字符串)
- 带有.NET 5支持的Visual Studio 2019(VS2019)
- Postman应用程序通过身份验证测试用例
行动顺序
1、使用支持.NET 5的VS2019打开解决方案GraphQL_DotNet.sln并构建解决方案。
2、使用SQL Server。为了简单起见,采用代码优先范式。在运行适当的服务或其集成测试时,会自动创建数据库UsersDb和PersonsDb。请调整appsettings.json服务配置文件中的连接字符串(如果需要)。首先,数据库中填充了代码中的多个初始记录。为了确保身份机制正常运行,所有这些记录均分配了负Id-s,但UsersDb.Users表不会在本工作中以编程方式更改。
3、GraphQlService的配置文件appsetting.json包含对象FeatureToggles:
"FeatureToggles": {"IsAuthJwt": true,"IsOpenApiSwagger": true,"IsGraphIql": true,"IsGraphQLPlayground": true,"IsGraphQLSchema": true
}
默认情况下,所有选项均设置为true。让我们先从没有身份验证的状态开始,然后将其"IsAuthJwt"设置为false。
4、开始GraphQlService。它可以从VS2019作为服务或在IIS Express下进行。具有GraphQL的带有Playground Web UI应用程序的浏览器将自动启动。
在Playground网页中,您可能会看到GraphQL模式,并使用不同的查询和变异。可以从文件querys-mutations-examples.txt复制一些预定义的查询和变异。
图4. Playground Web应用程序
您可以使用类似的GraphiQL Web应用程序代替Playground:在https://localhost:5001/graphiql上浏览。
图5. GraphiQL Web应用程序
5、Playground应用程序使用中间件来绕过响应GqlController(通常在开发过程中使用,但是在该项目中,所有版本都可用)。它不会调用客户在生产中使用的那个GqlController。要使用GqlController,您可以使用Postman应用程序。
在Postman中,使POST到https://localhost:5001/gql与Body-> GraphQL在QUERY文本框中提供您实际的GraphQL查询/变异的。
图6.使用Postman进行GraphQL查询
6、您也可以使用OpenApi(aka Swagger):浏览至https://localhost:5001/swagger:
图7. OpenApi(Swagger)
在Swagger网页中激活POST/Gql。
然后在Postman中,按右上角的Code链接:
图8. Postman的HTTP请求。
将查询复制到Swagger的Request body文本框并执行方法。
图9. POST/Gql请求。
图10. POST/Gql响应。
7、在所有情况下,您都可以使用不安全的调用方式进行http://localhost:5000 的说明和调试。
8、现在让我们使用JWT身份验证。停止运行GraphQlService(如果是),在GraphQlService的配置文件appsetting.json中的对象FeatureToggle设置"IsAuthJwt"为true,在VS2019,定义LoginService和GraphQlService为多启动项目并运行它们。
或者,可以通过从相应的Debug或Release目录中激活文件LoginService.exe和GraphQlService.exe来启动服务。在这种情况下,应在服务已经运行时手动启动浏览器在https://localhost:5001/playground上导航。
首先,您需要从Postman向https://localhost:5011/login发生一个POST,提供用户凭据username = "Super", password = "SuperPassword"。请注意端口5011:如您所见,LoginService监听该端口。
图11:登录
然后在Postman中打开一个新选项卡,以POST到https://localhost:5001/gql,打开Authorization-> Bearer Token,将登录时收到的令牌复制到Token文本框中,并通过单击Send按钮post。您可以使用OpenApi身份验证。为此,在OpenApi Web页面中, 按一下按钮Authorize(请参见图7),在Value文本框中插入单词“Bearer”,然后插入JWT令牌,然后按Authorize按钮。
9、集成测试可以在目录\\Test中的ServicesServiceTest项目中找到。
使用Playground的查询和变异
Playground是一个Web应用程序,可以由GraphQL库中间件立即激活(在这个例子中,使用NuGet包GraphQL.Server.Ui.Playground)。它提供了便捷、直观的方式来定义,记录和执行GraphQL查询和变异。Playground提供智能感知、错误处理和单词提示。它还显示了GraphQL模式以及可用于给定任务的所有查询和变异。Playground的屏幕截图如上图4所示。
这些是我们解决方案的查询和变异示例。您可能会在Playground DOCS窗格中看到其描述。
以下是Persons查询返回所有人。
query Persons {personQuery {persons {idgivenNamesurnameaffiliations {organization {nameparent {name}}role {name}}relations {p2 {givenNamesurname}kindnotes}}}
}
查询PersonById通过其唯一id参数返回一个人。在以下示例中,id将设置为1。
query PersonById {personByIdQuery {personById(id: 1) {idgivenNamesurnamerelations {p2 {idgivenNamesurname}kind}affiliations {organization {name}role {name}}}}
}
变异PersonMutation允许用户创建新人员或更新现有人员。
mutation PersonMutation {personMutation {createPersons(personsInput: [{givenName: "Vasya"surname: "Pupkin"born: 1990phone: "111-222-333"email: "vpupkin@ua.com"address: "21, Torn Street"affiliations: [{ since: 2000, organizationId: -4, roleId: -1 }]relations: [{ since: 2017, kind: "friend", notes: "*!", p2Id: -1 }]}{givenName: "Antony"surname: "Fields"born: 1995phone: "123-122-331"email: "afields@ua.com"address: "30, Torn Street"affiliations: [{ since: 2015, organizationId: -3, roleId: -1 }]relations: [{ since: 2017, kind: "friend", notes: "*!", p2Id: -2 }{ since: 2017, kind: "friend", notes: "*!", p2Id: 1 }]}]) {statusmessage}}
}
测验
集成测试位于项目ServicesTest(目录.\Tests)中。内存服务用于集成测试。这种方法大大减少了开发集成测试的工作。由于测试可以创建并最初填充数据库,因此它们可以开箱即用地运行。
结论
这项工作讨论了GraphQL技术在具有事务性数据存储库的CRUD操作中的用法,并介绍了在.NET 5 C#中开发的适当服务。它还使用内存服务实现了一些有用的功能,例如JWT身份验证、OpenApi、可配置的日志和集成测试。
https://www.codeproject.com/Articles/5295966/NET-5-Services-with-GraphQL-Data-Access-and-JWT
带有GraphQL数据访问和JWT身份验证的.NET 5服务相关推荐
- angular jwt_Angular5 JWT身份验证(Spring Boot安全性)
angular jwt 欢迎使用带有Spring Security的angular5 jwt身份验证.在本教程中,我们将在一个angular5单页应用程序中使用jwt身份验证创建一个全栈应用程序,该应 ...
- Angular5 JWT身份验证(Spring Boot安全性)
欢迎使用带有Spring Security的angular5 jwt身份验证.在本教程中,我们将在一个angular5单页应用程序中使用jwt身份验证创建一个完整的堆栈应用程序,该应用程序具有由spr ...
- Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step(二)
翻译自 Mohamad Lawand 2021年1月22日的文章 <Asp Net Core 5 Rest API Authentication with JWT Step by Step> ...
- ASP.NET Core与Dapper和VS 2017使用JWT身份验证WEB API并在Angular2客户端应用程序中使用它
目录 介绍 背景 步骤1 创建ASP.NET Core Web API项目 Fitness.JWT.API项目说明 使用代码 startup.cs JwtIssuerOptions.cs JwtCon ...
- 访问限制和身份验证和虚拟主机配置的三种方式
实验:配置访问限制和身份验证登录和三种方式配置虚拟主机访问 设置服务访问控制 限制策略规则 all 表示任意IP地址 Require all granted 允许所有主机访问 Require all ...
- Vue路由之axios配置JWT身份验证
前言: 认证和授权,其实吧简单来说就是:认证就是让服务器知道你是谁,授权就是服务器让你知道你什么能干,什么不能干(例如下面meta元信息),认证授权俩种方式:Session-Cookie与JWT,下面 ...
- 用户登入身份验证,手机app登入身份验证,TokenAuth身份验证,JSON Web Token(JWT)身份验证
JJWT身份验证 1.pom依赖: <dependency ...
- .Net WebAPI JWT身份验证
一.开发环境 VS2017 enterprise win10 Pro 64 .net 4.6.2 二.开发过程 1.使用VS2017 创建.netframework项目,选择WebApi 2.从Nu ...
- 如何使用Spring Security和Basic身份验证保护Jersey REST服务
在我之前的博客文章" 检查REST API是否有效的快速方法–从清单文件中获取GET详细信息"中 ,我展示了如何开发REST资源以轻松检查开发的REST API是否可用. 在本文中 ...
最新文章
- kubernetes性能测试实践
- Android 使用GridView+仿微信图片上传功能(附源代码)
- Git 笔记:基本操作工作流程
- Linux常用命令:FireWall
- 【你会用代码画年兽吗】20行代码使用JS实现虎年春节倒计时 —— 红红火火过虎年
- hbase sqoop 实验_SQOOP安装及使用-实验
- 强化学习《基于策略价值 - Pathwise Derivative Policy Grident》
- spark学习-62-Spark:Yarn-cluster和Yarn-client区别与联系
- mdk系列 Adsl 成功上网指南(非USB ADSL)
- ubuntu16 下安装freeswitch 1.8.3
- git学习笔记(2-git初始化配置)
- Windows 无法卸载IE9怎么办
- 招银网络-信息科技风险管理工程师-笔试-安全
- 安卓ROOT全教程(测试机 红米Note7Pro)
- 『Android开源控件』Banner广告图片轮播控件
- 1148 - 【入门】数数小木块
- Maven之快速入门
- 小米体脂秤2内部方案一览,附拆解维修记录
- python爬取豆瓣250排行榜数据
- AARRR模型 | 用户留存套路与习惯养成
热门文章
- springboot hibernate 缓存不更新_spring boot 整合 ehcache
- python语言的类型是_Python的语言类型
- 优秀案例|如何让网页首屏更具视觉吸引力?
- 海报设计素材模板|炫彩创意PSD分层时尚艺术海报 ​​​​
- 设计师值得拥有的设计导航
- 时尚精美电商专题首页设计PSD分层模板资源
- 只有1kb的清理软件_安卓手机总空间不足?试试这6个清理方法,瞬间多出几个G!...
- C++ protected 一种使用场景
- Python--Json数据简单解析(11.18)
- The X protocol C-language Binding (XCB) is a replacement for Xlib