使用 React hooks、.NET Core Web API 和 SQL Server 实现身份验证和授权
Implementing authentication and authorization with React hooks, .NET Core Web API, and SQL Server
我有一个使用 React hooks、SQL 服务器数据库和 .NET Core 3.1 Web API 构建的应用程序。我真的很难理解所有运动部件之间的关系。我想避免重新发明轮子并利用现有的库和框架。从我学到的知识来看,JWT 似乎是解决问题的方法,只是有点令人困惑。这是我的要求:
- 创建帐户并使用自定义站点帐户登录 in/out 或使用 Google/Facebook/Microsoft/etc。 (我可以从一个或另一个开始,但不想自己陷入困境并重写大量内容以添加另一个)
- 利用现有项目中的 .NET Core Identity 来处理 SQL 服务器数据库中的用户、角色等。
- 使用 React hooks 模式(如果必须的话,我可以通过翻译 class 组件来一瘸一拐)
我想我在所有的解耦中迷路了(这通常是一件好事!)我看到有关带有虚拟后端的 React 的文章,我迷路了。我看到有关 .NET Core 的帖子,但无法弄清楚如何将它与 React 一起使用。从概念上讲,大部分内容都有意义,但我还没有找到可以帮助我理解代码从头到尾应该是什么样子的地方。
这是我的问题!
- React前端应用和React auth服务是一回事吗?他们可以吗?一定是吗?
- JWT字符串是在React端生成还是.NET端生成?最好的图书馆?
- MS Identity Server 如何(或是否?)适合这个等式?
- 尽管看了大约 100 篇文章,但我并不完全理解刷新令牌的概念。是否需要 100% 刷新令牌? Benefits/drawbacks 到 using/not 使用它们?
要整理的东西很多,我只是希望有人能帮助我简化。
这个问题过于笼统,无法添加简单的答案。此外,回答您编号的问题很可能不会帮助您推进您的项目。因此,我试图在这里提供一个通用的答案。
创建帐户
由于您有一个带数据库的后端,因此必须在服务器上创建帐户。因此,您在 React 应用程序中捕获用户名和密码,然后将此数据发送到后端的注册端点。请注意,出于安全原因,您可能希望在发送之前对密码进行哈希处理,并且很可能无论如何它都会以这种方式存储在数据库中。
此时您的后端可以使用提交的数据进行验证(例如验证已经使用的用户名等)。如果详细信息有效,则将详细信息存储在数据库中。如果需要,您也可以在此处连接 MS IS。
存储帐户详细信息后,您可以使用 JWT 或任何其他库生成令牌。此令牌保存在服务器上,并 returned 在初始注册请求的响应中。也可以选择在此处 return 编辑刷新令牌。
令牌处理
注册请求应 return 一个授权令牌,以防注册成功。这个授权令牌(和可选的刷新令牌)应该存储在客户端(例如反应上下文,或者如果你正在使用像 redux 这样的状态管理库,那么你可以在全局状态中设置它)。
如果您想使用“记住我”,那么存储的令牌应该保存在客户端。
在此阶段,您的用户已登录。从现在开始,您将在所有请求的 header 中将此令牌发送到您的后端。然后您的后端可以使用存储在您的数据库中的令牌查找收到的令牌,并决定是否允许当前请求。
令牌刷新
出于安全原因,您可能希望为所有颁发的令牌设置 TTL。 IE。在一定时间后使令牌无效。当使用过期令牌的请求进入您的后端时,您 return 应该在客户端处理的过期响应。客户端应使用本地存储的刷新令牌调用刷新令牌。这应该会在服务器上生成一个新的身份验证令牌,并将旧令牌替换为新生成的令牌。
您可以将 TTL 设置为“永远保持”,在这种情况下您将不需要处理令牌刷新。
登录
您的 React 应用会捕获 user/password 并以与注册时相同的方式将其发送到您的后端。后端验证帐户详细信息并生成 return 一个新令牌。那么您的客户应该在注册时以与上述相同的方式使用此令牌。
还有数百万其他细节可以在这里解决,但可能足以让您开始。
React 应用程序中处理身份验证的部分自然应该是一个组件,然后由应用程序的其他部分导入(例如,由登录组件)。您可以查看示例教程 here.
JWT是在服务器端生成的,在你的例子中是.NET Core。它必须在服务器端创建,因为在客户端生成它意味着在那里有秘密,这样攻击者就可以窃取它并创建有效的令牌。另见 this answer.
至于生成:你可以自己生成,也可以使用认证框架(如IdentityServer4)或第三方认证(如使用Google登录)自动生成。如果你决定自己生成它,我认为你不需要复杂的东西(我的意思是,你甚至不需要像 JWT.NET). Just use a simple tutorial, like this one.
这样的库
IdentityServer4是一个认证框架,实现了OpenID Connect和OAuth 2.0协议,默认使用JWT认证。
使用它将获得身份验证行为,包括例如登录和注销(它实际上带有自己的登录页面(Login.cshtml
,Logout.cshtml
)),但不包括注册。
建议单独将其用于此目的,并且您可以建议以下两个答案以更好地理解处理身份验证时的关注点分离(尽管问题的标题指的是用户创建,但答案也专门针对身份验证):
如果您想为您的应用增加更多安全性,您将在您的 JWT 中有一个 exp
声明。如果您有一个 exp
声明并且不希望清晰的用户每次他们的 JWT 过期时都必须 re-login,您将拥有刷新令牌。您使用刷新令牌来获取全新的访问令牌。
如果您将使用 IdentityServer4,刷新令牌已经为您实现,但您必须明确配置它们。建议以下来源:
- IdentityServer4 refresh tokens documentation.
- 一个 complete tutorial 也解释了如何使用刷新令牌。
此外,我不知道您阅读的那 100 篇文章是什么 :) 但我认为以下 SO 帖子很棒:
我有一个使用 React hooks、SQL 服务器数据库和 .NET Core 3.1 Web API 构建的应用程序。我真的很难理解所有运动部件之间的关系。我想避免重新发明轮子并利用现有的库和框架。从我学到的知识来看,JWT 似乎是解决问题的方法,只是有点令人困惑。这是我的要求:
- 创建帐户并使用自定义站点帐户登录 in/out 或使用 Google/Facebook/Microsoft/etc。 (我可以从一个或另一个开始,但不想自己陷入困境并重写大量内容以添加另一个)
- 利用现有项目中的 .NET Core Identity 来处理 SQL 服务器数据库中的用户、角色等。
- 使用 React hooks 模式(如果必须的话,我可以通过翻译 class 组件来一瘸一拐)
我想我在所有的解耦中迷路了(这通常是一件好事!)我看到有关带有虚拟后端的 React 的文章,我迷路了。我看到有关 .NET Core 的帖子,但无法弄清楚如何将它与 React 一起使用。从概念上讲,大部分内容都有意义,但我还没有找到可以帮助我理解代码从头到尾应该是什么样子的地方。
这是我的问题!
- React前端应用和React auth服务是一回事吗?他们可以吗?一定是吗?
- JWT字符串是在React端生成还是.NET端生成?最好的图书馆?
- MS Identity Server 如何(或是否?)适合这个等式?
- 尽管看了大约 100 篇文章,但我并不完全理解刷新令牌的概念。是否需要 100% 刷新令牌? Benefits/drawbacks 到 using/not 使用它们?
要整理的东西很多,我只是希望有人能帮助我简化。
这个问题过于笼统,无法添加简单的答案。此外,回答您编号的问题很可能不会帮助您推进您的项目。因此,我试图在这里提供一个通用的答案。
创建帐户
由于您有一个带数据库的后端,因此必须在服务器上创建帐户。因此,您在 React 应用程序中捕获用户名和密码,然后将此数据发送到后端的注册端点。请注意,出于安全原因,您可能希望在发送之前对密码进行哈希处理,并且很可能无论如何它都会以这种方式存储在数据库中。 此时您的后端可以使用提交的数据进行验证(例如验证已经使用的用户名等)。如果详细信息有效,则将详细信息存储在数据库中。如果需要,您也可以在此处连接 MS IS。 存储帐户详细信息后,您可以使用 JWT 或任何其他库生成令牌。此令牌保存在服务器上,并 returned 在初始注册请求的响应中。也可以选择在此处 return 编辑刷新令牌。
令牌处理
注册请求应 return 一个授权令牌,以防注册成功。这个授权令牌(和可选的刷新令牌)应该存储在客户端(例如反应上下文,或者如果你正在使用像 redux 这样的状态管理库,那么你可以在全局状态中设置它)。
如果您想使用“记住我”,那么存储的令牌应该保存在客户端。
在此阶段,您的用户已登录。从现在开始,您将在所有请求的 header 中将此令牌发送到您的后端。然后您的后端可以使用存储在您的数据库中的令牌查找收到的令牌,并决定是否允许当前请求。
令牌刷新
出于安全原因,您可能希望为所有颁发的令牌设置 TTL。 IE。在一定时间后使令牌无效。当使用过期令牌的请求进入您的后端时,您 return 应该在客户端处理的过期响应。客户端应使用本地存储的刷新令牌调用刷新令牌。这应该会在服务器上生成一个新的身份验证令牌,并将旧令牌替换为新生成的令牌。
您可以将 TTL 设置为“永远保持”,在这种情况下您将不需要处理令牌刷新。
登录
您的 React 应用会捕获 user/password 并以与注册时相同的方式将其发送到您的后端。后端验证帐户详细信息并生成 return 一个新令牌。那么您的客户应该在注册时以与上述相同的方式使用此令牌。
还有数百万其他细节可以在这里解决,但可能足以让您开始。
React 应用程序中处理身份验证的部分自然应该是一个组件,然后由应用程序的其他部分导入(例如,由登录组件)。您可以查看示例教程 here.
JWT是在服务器端生成的,在你的例子中是.NET Core。它必须在服务器端创建,因为在客户端生成它意味着在那里有秘密,这样攻击者就可以窃取它并创建有效的令牌。另见 this answer.
这样的库
至于生成:你可以自己生成,也可以使用认证框架(如IdentityServer4)或第三方认证(如使用Google登录)自动生成。如果你决定自己生成它,我认为你不需要复杂的东西(我的意思是,你甚至不需要像 JWT.NET). Just use a simple tutorial, like this one.IdentityServer4是一个认证框架,实现了OpenID Connect和OAuth 2.0协议,默认使用JWT认证。
使用它将获得身份验证行为,包括例如登录和注销(它实际上带有自己的登录页面(Login.cshtml
,Logout.cshtml
)),但不包括注册。
建议单独将其用于此目的,并且您可以建议以下两个答案以更好地理解处理身份验证时的关注点分离(尽管问题的标题指的是用户创建,但答案也专门针对身份验证):如果您想为您的应用增加更多安全性,您将在您的 JWT 中有一个
exp
声明。如果您有一个exp
声明并且不希望清晰的用户每次他们的 JWT 过期时都必须 re-login,您将拥有刷新令牌。您使用刷新令牌来获取全新的访问令牌。 如果您将使用 IdentityServer4,刷新令牌已经为您实现,但您必须明确配置它们。建议以下来源:- IdentityServer4 refresh tokens documentation.
- 一个 complete tutorial 也解释了如何使用刷新令牌。
此外,我不知道您阅读的那 100 篇文章是什么 :) 但我认为以下 SO 帖子很棒: