基于REACT和.NET CORE集成WINDOWS身份验证

有很多方法可以向您的应用程序添加身份验证。虽然OAuth是最常见的一种,但这并不是您唯一的选择。今天,我将向您展示如何通过React和.NET Core简单地完成Windows身份验证。

探索我们的选择

在深入探讨之前,让我们简要讨论一些可用的其他选项。了解您的选择,可以使您根据自己的情况做出最佳(受过良好教育)的决定。这绝不是关于替代方案的详尽讨论,而只是其中一些较流行的替代方案。

Okta是一家身份和访问管理公司,提供基于云的解决方案。他们有Active Directory的插件/提供程序。他们的站点包含一个教程,如何开始向您的React应用程序添加身份验证。在商业解决方案方面,该解决方案经常被推荐使用。

Auth0是另一个具有良好关注度的商业解决方案。他们有专门针对将Active Directory / LDAP与React结合使用的教程。

IdentityServer是开源替代方案。就像其他人一样,他们提供了有关如何实施Windows身份验证的说明。他们有一个有关如何实现javascript客户端(例如React)的示例。这是有关在Identity Server 4中使用SPA(反应/角度)UI的文章。

当然,我们今天在这里讨论的选择是推出您自己的解决方案。

为什么不选择交钥匙解决方案?

尽管您的原因可能有所不同,但我想出了一些原因。

  1. 基础结构/资源不足,无法设置服务(适用于Identity Server 4)。

  2. 资金/预算不足,无法支付SAAS提供商的费用。

  3. 您位于防火墙之内,并且React和.NET应用程序都位于同一网络上。

  4. 您喜欢挑战和/或喜欢重新发明轮子(哈!)

好的,也许最后一个有点有趣。一般来说,使用交钥匙解决方案最好的选择,但不是您的选择。在我遇到的这个特殊用例中,这不是我想要的。然而。

入门

为了构建此应用程序,我们需要两件事:

  1. .NET Core API项目–该项目将处理身份验证,授权以及API调用

  2. React应用程序–该项目是我们的GUI

我为该项目学习和应用的东西是Google-fu精通和反复试验编码的结合。希望汇总我的经验将使您(我的读者)比我更容易。

我首先创建一个文件夹来包含我的API和React项目,然后运行dotnet new api -o ReactWindowsAuth以搭建一个新的API项目。(这实际上是一个谎言,我使用VS来创建应用程序,但是我们假装使用了CLI)。从那里开始,我运行npm create-react-app test-app了一个名为的基本React应用程序test-app。就个人而言,我喜欢将Visual Studio用于.NET代码,将VSCode用于几乎所有其他内容,因此我在VS中打开了新的API项目并生成了解决方案文件。

从这里开始,我们现在可以开始使用React和.NET Core实施Windows身份验证了!

框架.NET Core API

我们需要做的第一件事就是确保我们的应用程序以Windows身份验证运行。由于我使用VS生成了项目并提供了Docker支持,因此我不得不做一些您可能不需要做的事情。

启用Windows身份验证

我要做的第一件事是将调试启动器从Docker切换到IIS Express。

切换默认启动

接下来,我需要打开我的launchSettings.json"windowsAuthentication": trueiisSettings下进行设置。

启用Windows身份验证

好吧,让我们稍等一秒钟。为了使Windows身份验证起作用,您将需要在IIS或IIS Express中进行托管。您也可以使用Kestrel和HTTP.sys托管来完成此操作,但出于本文的方便,让我们集中讨论IIS Express。如果您想使它在Docker和/或Linux上运行,您将要使用Kestrel。

我们的应用程序现在可以与Windows身份验证一起使用了,但是如果我们现在启动它,它仍然不会使用。我们还有很多工作要做。

配置Windows身份验证

现在我们已经设置了API以通过IIS使用Windows身份验证,我们需要使API本身意识到这一点。为此,我们需要对进行一些调整Startup.cs。MSDN上有文档,但我们也可以在这里进行阅读。

您需要做的第一件事是services.AddAuthentication(IISDefaults.AuthenticationScheme);在您的ConfigureServices方法中添加任何位置。这利用了Microsoft.AspNetCore.Server.IISIntegration命名空间。

添加Windows身份验证

接下来,您需要配置Windows身份验证需要保护哪些控制器或动作。顺便说一下,这就是为什么我们"anonymousAuthentication": true独自留在launchSettings.json。这里的一个用例是,如果您使用的是Swagger,并且希望匿名访问文档并且仅保护API本身。

在我的用例中,我假装我希望所有API控制器都需要身份验证。鉴于此,我创建了一个WebControllerBase.cs,并用[Authorize]属性对其进行了装饰。请注意,您可以改为用[Authorize]标记每个控制器。就是说,我的理由实际上是押韵的,在以后的第二部分中,我将进一步阐述这个想法。现在,只需滚动即可。

WebControllerBase,将[Authorize]标记为需要身份验证

接下来,只需让我们现有的控制器和新控制器继承自WebControllerBase而不是即可ControllerBase

现在,我们现有的控制器继承自WebControllerBase

在网络上的其他示例中,您可能会看到人们说您需要添加app.UseAuthentication()Configure(IApplicationBuilder app, IWebHostEnvironment env)方法。如果仅针对IIS / IIS Express,则不会。也就是说,添加它不会伤害您。我不会判断你是否愿意。我的源代码有它。

测试一下!

现在,我们可以对其进行测试了。在WeatherForecastController顶部打一个断点:以调试模式获取并运行Web应用程序。达到断点时,添加监视HttpContext.User并向下钻取.Identity.Name。(可选)只需在方法顶部添加此行:var user = HttpContext.User?.Identity?.Name ?? "N/A";并查看结果。您的应用程序现在正在报告您当前的Windows用户名,对吗?

哇,等等,您还没有完成!

我们已经接近了,但是如果我们想在React中使用它,我们还有很多工作要做。CORS。别说了。什么是CORS?CORS是跨域资源共享,这是您要允许[this]访问[that]的一种非常真实的方式。在现实世界中,默认情况下将浏览器配置为禁止通过脚本发起的HTTP请求,除非接收端明确允许。

所以……让我们做一下,这样这个API可以接受来自React应用程序的CORS请求,对吧?我们不会在这里变得很花哨。为了使此操作生效,我们需要在中添加一些设置,appsettings.json然后在中进行其他设置Startup.cs

appsettings.json

首先,我们去appsettings.json添加以下内容:"CorsOrigins": [ "http://localhost:3000" ],。是的,它是数组类型。为什么?主要是因为它为您提供了选择。假设在开发中,我打开了通往机器的通道,以便某人(甚至我)可以从另一台设备访问该应用程序。显然,它们不会通过本地主机名或IP地址连接到localhost。所有这些都是我可能要设置的选项。

启动文件

接下来,我们需要将CORS添加到我们的服务和中间件中。在ConfigureServices中,请添加以下代码:

// add this class somewhere outside of the Startup class
public class Constants
{
public const string CORS_ORIGINS = "CorsOrigins";
}services.AddCors(opt =>
{
opt.AddPolicy("CorsPolicy", builder => builder.AllowAnyHeader().AllowAnyMethod().WithOrigins(Configuration.GetSection(Constants.CORS_ORIGINS).Get<string[]>()).AllowCredentials());
});

此代码的简要说明。它允许传递任何标头,使用任何http方法(GET,POST,PUT,DELETE等),必须来自配置中特定的来源之一,并允许在标头中传递凭据。在您自己的应用程序中,您可以更改许多设置。您可能不会更改其中任何一个。至少您现在知道它们了。

接下来,我们需要添加app.UseCors("CorsPolicy")到我们的Configure(app, env)方法中。请注意,这是中间件和中间件顺序。在这种情况下,它需要跟从app.UseRouting()但在此之前app.UseAuthentication()app.UseAuthorization()。顺便说一句,如果您添加了中间件,但中间件工作不正常,则应检查其注册顺序。

现在使用app.UseCors(“ CorsPolicy”)配置方法

现在我们准备好让我们的React应用程序与Windows身份验证挂钩了!

带有React的Windows身份验证–连接起来!

对此感到兴奋吗?我知道我是。这比您想象的要容易。准备好了吗?

您需要做的就是在fetch请求中添加两个属性:credentials: "include"mode: 'cors'

将会发生的情况是,如果您访问的站点与您不在同一域(或计算机)上,则浏览器将提示您输入该Active Directory,LDAP或计算机实例的凭据。成功进行身份验证后,浏览器将其存储以备将来使用。如果您在完全相同的计算机或域上,则不会提示凭据。

话虽如此,您可以(并且可能应该)设置服务f调用的方式,因此不必在各处都输入相同的垃圾。当我第一次开始使用React时,我很快意识到,设置一些获取帮助程序来启动它比较容易。我意识到的第二件事是,在React代码中将所有.NET API控制器与“服务”进行匹配更加容易。

考虑到这一点,让我们看一下我的提取帮助器和示例服务。

fetch-helpers.js

这是我在此测试应用程序中拥有的一些基础知识:

export const handleResponse = (response) => {return response.text().then((text) => {const data = text && JSON.parse(text);if (!response.ok) {const error = (data && data) || response.statusText;return Promise.reject(error);}return data;});
};export const requestBase = (() => {if (typeof window !== "undefined") {return {method: "POST",credentials: "include",mode: 'cors',headers: new Headers({Accept: "application/json","Content-Type": "application/json",}),};} elsereturn {method: "POST",credentials: "include",// mode: 'cors',headers: {Accept: "application/json","Content-Type": "application/json",},};
})();

值得注意的是,requestBase如果它不是NodeJS(经过渲染的React),则可以具有不同的返回对象。很难发现差异,但是无浏览器版本将标头设置为Headers对象的实例,而浏览器版本仅设置JSON对象。

weather-api.js

接下来,让我们看看我们的服务如何使用fetch-helpers。首先,下面的apiBase是完整的URL。显然,您不会这样做,但实际上会将React的baseUrl设置为更高的级别(通常在HTML级别)。这是示例代码,请加一点盐。

import { handleResponse, requestBase } from "../_helpers";const apiBase = "https://localhost:44387/weatherforecast";class WeatherForecastService {getForecasts() {let request = Object.assign({}, requestBase, { method: "GET" });let url = `${apiBase}`;return fetch(url, request).then(handleResponse);}getProtectedForecast() {let request = Object.assign({}, requestBase, { method: "GET" });let url = `${apiBase}/5`;return fetch(url, request).then(handleResponse);}
}const instance = Object.freeze(new WeatherForecastService());
export { instance as WeatherForecastService };

我在这里所做的只是公开我希望React可以访问的方法,将它们包装在baseRequestfrom的周围,并fetch-helpers使用我的handleResponsefrom 来处理响应fetch-helpers,然后传递回调用方。

最后但同样重要的是,将其连接起来!

现在我们已经铺设了所有管道,现在该连接所有东西了。我只是直接编辑App.js。告我。对于该示例,我将导入所有三个API服务文件,然后const为我要处理的每个按钮设置一些功能。其中的每一个都仅注销到控制台,而不用花费大量精力。最后,当然是按钮本身。由于该文件在修改后相当庞大,因此我仅摘录了按钮事件之一以及调用它的React按钮组件本身。

const getProtectedForecast = () => {
console.log("attempting...");WeatherForecastService.getProtectedForecast().then((response) => {
console.log("response: ", JSON.stringify(response));
console.log("oh boy!");}).catch((err) => {
console.error(err);});
};<button type="button" onClick={getProtectedForecast}>
Get protected forecast
</button>

重要环节– Windows身份验证基于角色的安全性

虽然上述设置是非常基本的,但它缺少一个非常重要的部分,不是吗?基于角色的安全性。在这里考虑一下此内容,这是对第2部分的非常简短的介绍,而我将在不久的将来写一篇文章。如果你已经点击周围的代码,而阅读这篇文章,你可能已经注意到在Startup.cs以下行:ConfigureServices:services.AddTransient();。如果您没有注意到它,那是可以的,因为我现在将谈论它。

在对用户进行身份验证之后但在获得授权之前,授权提供者将调用您的自定义IClaimsTransformation实现(如果提供)。参见MSDN。在我的实现中(位于中ClaimsTransformer),您将看到我只是在随意添加角色“ Super-awesome”作为我们WindowsIdentity用于其声明类型的相同声明类型。

IClaimsTransformation的ClaimsTransformer实现者

接下来,您可能已经注意到WeatherForecastController我添加了一个GetAnother方法调用,该方法调用需要“超级棒”角色。在此之下,我还添加了一种GetFail方法,该方法将始终失败,因为用户不在“管理员”角色中。这些方法都没有连接到React应用程序中,并且要求您直接在浏览器中单击它们以查看它们是否有效(或可能无效)。

基于Controller动作的基于角色的Windows身份验证

结论

将Windows身份验证连接到您的React应用程序并不困难。这也是非常基本的。交钥匙解决方案可以使您走得更快,更远,但是如果您没有基础设施或现金,仍然可以自己动手做。和往常一样,我博客文章中的代码可以在GitHub上找到。

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

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

相关文章

.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书

简介加解密现状&#xff0c;编写此系列文章的背景&#xff1a;需要考虑系统环境兼容性问题&#xff08;Linux、Windows&#xff09;语言互通问题&#xff08;如C#、Java等&#xff09;&#xff08;加解密本质上没有语言之分&#xff0c;所以原则上不存在互通性问题&#xff09;…

leetcode115. 不同的子序列

一&#xff1a;题目 二:代码 class Solution { public:/**思路:动规分析走一波1>:确定dp数组以及下标的含义dp[i][j] 表示的是 以下标i-1结尾的子序列s中出现以j-1结尾的子序列t的 个数2>:确定dp数组的状态递推公式这里考虑两种状况 一种就是 s[i-1] s[j-1] 一种就是字…

ASP.NET Core 3.x启动时运行异步任务(二)

这一篇是接着前一篇在写的。如果没有看过前一篇文章&#xff0c;建议先去看一下前一篇&#xff0c;这儿是传送门一、前言前一篇文章&#xff0c;我们从应用启动时异步运行任务开始&#xff0c;说到了必要性&#xff0c;也说到了几种解决方法&#xff0c;及各自的优缺点。最后&a…

leetcode583. 两个字符串的删除操作

一:题目 二:上码 class Solution { public:/**思路:题目给的是让求最值,那么首先就会想到的是动态规划,我们想得到答案的结果其实有多个的&#xff0c;但是我们是取最小的步数动态规划 五步走:1>:确定dp数组以及下标的含义dp[i][j]表示的是 以下标i-1结尾的字符串word1,和…

C# 中居然也有切片语法糖,太厉害了

一&#xff1a;背景 1. 讲故事昨天在 github 上准备找找 C# 9 又有哪些新语法糖可以试用&#xff0c;不觉在一个文档上看到一个很奇怪的写法: foreach (var item in myArray[0..5]) 哈哈&#xff0c;熟悉又陌生&#xff0c;玩过python的朋友对这个 [0..5] 太熟悉不过了&#x…

跟我一起学.NetCore之中间件(Middleware)简介和解析请求管道构建

前言中间件(Middleware)对于Asp.NetCore项目来说&#xff0c;不能说重要&#xff0c;而是不能缺少&#xff0c;因为Asp.NetCore的请求管道就是通过一系列的中间件组成的&#xff1b;在服务器接收到请求之后&#xff0c;请求会经过请求管道进行相关的过滤或处理&#xff1b;正文…

leetcode647. 回文子串

一&#xff1a;题目 二&#xff1a;上码 class Solution { public:/**思路:动态规划五步走1>:确定dp数组以及下标的含义dp[i][j] 表示的是在[i,j]范围内的字串 是否是 回文子串&#xff0c;如果是的话那么dp[i][j] true2>确定dp数组的状态转移方程那么就有两种情况 s[i…

leetcode516. 最长回文子序列

一:题目 二:上码 class Solution { public:/**思路:1.分析题意 这个是让我们求最值,那么首先想到动态规划2.动态规划1>:确定dp数组以及下标的含义dp[i][j] 表示字符串在[i,j]范围内的最长回文子序列2>:确定dp数组的状态递推公式那么就是s[i] 与 s[j] 相等 不相等两种情况…

C#刷剑指Offer | 二叉搜索树的后序遍历序列

【C#刷题】| 作者 / Edison Zhou这是EdisonTalk的第289篇原创内容我们来用之前学到的数据结构知识来刷《剑指Offer》的一些核心题目&#xff08;精选了其中30道题目&#xff09;&#xff0c;希望对你有帮助&#xff01;本文题目为&#xff1a;二叉搜索树的后序遍历序列。1题目介…

leetcode739. 每日温度

一:题目 二:上码 // class Solution { // public: // vector<int> dailyTemperatures(vector<int>& temperatures) { // vector<int> ans(temperatures.size(),0);// for (int i 0; i < temperatures.size(); i) {// …

Leetcode周赛复盘——第 71 场力扣双周赛与第 279 场力扣周赛

双周赛&#xff1a; 5984. 拆分数位后四位数字的最小和 class Solution:def minimumSum(self, num: int) -> int:a, b, c, d sorted(list(map(int, str(num))))return 10 * (a b) c dstr(num)得到字符串序列&#xff0c;然后用map函数对序列的每个字符转换为数字&…

使用SWAGGER和ASP.NET CORE设置可选路由参数

使用SWAGGER和ASP.NET CORE设置可选路由参数根据OpenAPI 3.0&#xff0c;这是不可能的。但是&#xff0c;如果您真的希望成为现实呢&#xff1f;您是否必须解决并允许您的Swagger文档出错&#xff1f;我在这里向您展示如何使用Swagger和ASP.NET Core设置可选的路由参数。等等&a…

在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言)

在一维数组中的考察中&#xff0c;最常见的就是找出数组中的重复数、只出现一次的数或者丢失&#xff08;消失&#xff09;数等等。 一般来说&#xff0c;首先想到的就是用哈希表&#xff08;集合&#xff09;来记录出现过的数&#xff0c;基本所有的题都可以用集合来做&#…

Confluent官博:Kafka最牛队列,性能15倍于RabbitMQ!

“容器、Kubernetes、DevOps、微服务、云原生&#xff0c;这些技术名词的频繁出现&#xff0c;预兆着新的互联网技术时代的到来&#xff0c;大数据高并发将不再遥远&#xff0c;而是大部分项目都必须面对的&#xff0c;消息队列则是核心利器&#xff01;成熟的消息队列产品很多…

leetcode503. 下一个更大元素 II

一:题目 二:上码 class Solution { public:/**思路: 1.将两个nums拼接到一块这里拼接到一块,当我们最后的元素找不到比其大的时候 就会开始从头开始这样的话就可以继续进行 入栈 或者出栈的操作入栈就是比我栈顶小的元素&#xff0c;出栈的话 那就是 找到了比其大的元素了…

跟我一起学.NetCore之中间件(Middleware)应用和自定义

前言Asp.NetCore中的请求管道是通过一系列的中间件组成的&#xff0c;使得请求会根据需求进行对应的过滤和加工处理。在平时开发中会时常引用别人定义好的中间件&#xff0c;只需简单进行app.Usexxx就能完成中间件的注册&#xff0c;但是对于一些定制化需求还得自己进行处理和封…

leetcode42. 接雨水

一:题目 二:上码 // class Solution { // public: // /**超时 // 思路: // 1.我们按列来计算 这就是表明的是 我们求取接雨水 向上的高度就是雨水量 // 但是这里的话我们的需要对雨水的高度 来进行判定 // 2.那么如何判定…

Magicodes.IE之导入导出筛选器

总体设计Magicodes.IE是一个导入导出通用库&#xff0c;支持Dto导入导出以及动态导出&#xff0c;支持Excel、Word、Pdf、Csv和Html。在本篇教程&#xff0c;笔者将讲述如何使用Magicodes.IE的导入导出筛选器。在开始之前&#xff0c;我们需要先了解Magicodes.IE目前支持的筛选…

谈了千百遍的缓存数据的一致性问题

“灵魂拷问保证缓存和数据库的一致性很简单吗&#xff1f;有哪些方式能保证缓存和数据库的一致性呢&#xff1f;如果发生了缓存和数据库数据不一致的情况怎么办呢&#xff1f;在上篇文章我们介绍了缓存的定义分类以及优缺点等&#xff0c;如果还没看的同学可以移步这里听说你会…

BS作业 基于springboot + Thymeleaf +mybatis 实现的书城管理系统

一:项目背景 项目描述 一个基本功能较为完整的后台管理项目。项目主要功能有&#xff1a;登录验证&#xff0c;登录功能还加入了随机验证码的验证&#xff1b; 用户注册&#xff0c;注册中密码基于srping 安全框架提供的加密(自动加盐)的密码储存方式&#xff0c;对注册重名进…