【复杂系统迁移 .NET Core平台系列】之认证和授权

源宝导读:微软跨平台技术框架—.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件。本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验。

一、背景

   随着ERP的产品线越来越多,业务关联也日益复杂,应用间依赖关系也变得错综复杂,单体架构的弱点日趋明显。19年初,由于平台底层支持了分应用部署模式,将ERP从应用子系统层面进行了切割分离,迈出了从单体架构向微服务架构转型的坚实一步。不久的将来,ERP会进一步将各业务拆分成众多的微服务,而微服务势必需要进行容器化部署和运行管理,这就要求ERP技术底层必须支持跨平台,所以将现有ERP系统从.NET Framework迁移到 .NET Core平台势在必行。

    上一篇我们讲述了Erp改造.Net Core之静态文件,这一篇我们将讲述在认证和授权改造过程中遇到的问题和解决思路。

二、关于认证和授权

    权限控制是应用程序中最常见的需求,无论是在Asp.Net还是Asp.Net Core中都有相应的支持,而权限控制在框架层面支持主要是两部分,身份认证和身份授权:

  • 身份认证:识别当前请求的用户信息,一般是通过加密的Cookies实现。

  • 身份授权:识别当前请求是否有访问指定资源的权限,一般是根据当前请求识别的用户信息,结合角色权限相关配置来判断。

三、Asp.Net认证和授权的实现

    这里不区分Asp.Net WebForm和Asp.Net MVC,因为两者都是基于HttpModule来进行身份认证和授权。

   在Asp.Net中认证是通过FormsAuthenticationModule实现,授权是通过UrlAuthorizationModule实现,需要在web.config中做如下配置:

<system.web><authentication mode="Forms"><forms loginUrl="/PubPlatform/Login/index.aspx" name="userToken" defaultUrl="/PubPlatform/Nav/Home/Default.aspx" timeout="300" /></authentication><authorization><deny users="?" /><!--禁止匿名用户的访问--></authorization>
</system.web><!--管理员有modeling目录的访问权限-->
<location path="modeling"><system.web><authorization><allow roles="Admin"/><deny users="*"/></authorization></system.web>
</location>

    简述一下用户访问网站授权一个流程:

  1. 假设用户访问首页/PubPlatform/Nav/Home/Default.aspx。

  2. UrlAuthorizationModule 根据禁止匿名用户访问的配置,要求用户进行身份认证。

  3. 跳转到登陆页面/ PubPlatform/ Login/index.aspx进行身份认证。

  4. 服务端判断用户输入用户密码信息。

  5. 如果验证通过将认证信息写入Repsonse的Cookies中并跳转到/PubPlatform/Nav/Home/Default.aspx。

  6. UrlAuthorizationModule 根据配置发现已经有用户信息直接,开始进入到HttpHandler处理程序。

PS:整个认证过程远比这个复杂,因为本文重点不在这里,只做简单的描述,了解基本流程即可,有兴趣可以参考https://www.cnblogs.com /fish-li/archive/2012/04/15/2450571.html。

    第二段配置中,通过用户所在的组来控制是否有modeling目录的访问权限,如果需要更多的权限配置可以添加更多类似的配置,实际在使用过程中很少使用这种方式,因为用户角色和页面会有很多,配置会很多而且不能实现动态配置,所以一般是在应用程序中处理,在Webform中一般采用类似如下方式:

public class BacePage:Page
{protected override void OnLoad(EventArgs e){//在这里根据HttpContext.User来获取用户信息然后获取角色权限来判断当前资源可否访问base.OnLoad(e);}
}

    在Mvc中一般采用继承自AuthorizationFilterAttribute来处理,逻辑跟上述代码中演示的类似。

四、Asp.Net Core

    在Core中引入Authentication需要在Startup.cs进行引入,一般和老版本一样使用Cookies做认证信息的承载,承载的代码如下:

public void ConfigureServices(IServiceCollection services)
{...services.AddAuthentication("Cookies").AddCookie("Cookies");...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{...app.UseAuthentication();...
}

    在ConfigureServices(应用初始化过程),引入了Cookies作为默认的认证方式,在Configure(管道初始化)过程中引入认证的中间件。下面会简要分析下认证和授权的过程:

  1. 请求进入Authentication Middleware中间件之后首先会IAuthentication RequestHandler 接口做权限判断,这个组件主要使用来做远程认证的,例如SSO登录的场景。然后再做默认的认证:以Cookies认证为例,主要是读取Cookies的信息到HttpContext.User中。

  2. 经过中间件之后会进入AuthorizeFilter中(这里和认证和授权的核心地方)。

  3. 获取全局,Controller,Action之上的元数据计算之后得出AuthorizationPolicy。

  4. 通过IPolicyEvaluator调用Authentication模块进行认证信息解析。

  5. 通过IPolicyEvaluator携带Authentication结果调用Authentization模块进行授权信息解析。

    核心代码如下:

//AuthenticationMiddleware 部分代码
public async Task Invoke(HttpContext context)
{context.Features.Set(new AuthenticationFeature{OriginalPath = context.Request.Path,OriginalPathBase = context.Request.PathBase});// Give any IAuthenticationRequestHandler schemes a chance to handle the requestvar handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()){var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;if (handler != null && await handler.HandleRequestAsync()){return;}}var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();if (defaultAuthenticate != null){var result = await context.AuthenticateAsync(defaultAuthenticate.Name);if (result?.Principal != null){context.User = result.Principal;}}await _next(context);
}
// AuthorizeFilte部分代码
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{if(context == null){throw new ArgumentNullException(nameof(context));}if (!context.IsEffectivePolicy(this)){return;}// IMPORTANT: Changes to authorization logic should be mirrored in security's AuthorizationMiddlewarevar effectivePolicy = await GetEffectivePolicyAsync(context);if (effectivePolicy == null){return;}var policyEvaluator = context.HttpContext.RequestServices.GetRequiredService<IPolicyEvaluator>();var authenticateResult = await policyEvaluator.AuthenticateAsync(effectivePolicy, context.HttpContext);// Allow Anonymous skips all authorizationif (HasAllowAnonymous(context)){return;}var authorizeResult = await policyEvaluator.AuthorizeAsync(effectivePolicy, authenticateResult, context.HttpContext, context);if (authorizeResult.Challenged){context.Result = new ChallengeResult(effectivePolicy.AuthenticationSchemes.ToArray());}else if (authorizeResult.Forbidden){context.Result = new ForbidResult(effectivePolicy.AuthenticationSchemes.ToArray());}
}

    如果有兴趣的话可以继续往里面跟踪一下代码发现最终起作用的是IAuthentication Handler和IAuthorizationHandler,而最终这两个Handler的引入在Core中对应两个概念:

  • AuthenticationScheme 认证计划。

  • AuthorizationRequirement 授权条件。

    最终Core的认证和授权一般都是通过这两个来进行扩展,这里特别说明一点,在Mvc Core中将身份认证和授权进行了统一的规划。因为在认证过程中,MVC Core只是只是解析,但并不实际将Http请求进行返回处理。实际过程是在AuthorizationRequirement进行处理的,这里特别提到Mvc Core中的默认授权DenyAnonymousAuthorizationRequirement,通过这个授权条件判断是否有认证的用户信息来进行权限的判断。

资源能否访问这个理解为授权,那么身份认证只是授权的一种方式。

    在Asp.Net WebFrom中使用基于HttpModule进行身份认证会丢失掉很多元数据的信息,因为最终方法的执行是在HttpHandler上,而HttpModule并不知道那个Handler也不知道是那个方法,就会大量使用HttpContext的解析,提高了复杂度。

    如果在HttpModule中进行,如果有多种身份认证方式,那么无论最终资源需要何种方式都会经过很多HttpModule,走了无谓的分支。

    另外Webfrom中授权一般写在基类中,基类必定会引入不同的继承分支,这样也不便于维护.对比Mvc Core中使用的特性标记+策略者的使用方式,更加利于维护和扩展,而不用对原有逻辑进行变动。

    对比Asp.Net MVC中其中有IAuthenticationFilter和IAuthorizationFilter来处理授权和认证,然而在Asp.Net MVC Core中 只有IAuthorizationFilter。

    对于资源的访问应该只有可否访问的判断即授权,而是否身份认证只能说是判断授权一种常用方式,在MVC Core中将认证通过DenyAnonymousAuthorizationRequirement融入授权以后,真正的将授权和认证融为一体,而非之前看似两个并行的概念,相互不同的处理逻辑。

    在Mvc Core通过AOP进行接入,然后一系列的封装,最终将身份和授权通过Scheme + IAuthrenticationHandler和Requirement + AuthorizationHandler,这种类似于策略者模式的方式,对外提供扩展。更加易于扩展,而实际并不用太多考虑AOP部分的逻辑。最终授权和认证之需要我们进行Attribute标记然后MVC Core会自动加载到自己的元数据中,另外在RazorPage还可以主动调用如下方法进行授权的添加:

//对目录进行授权
RazorPageOptions.Conventions.AuthorizeFolder();
//对页面进行授权
RazorPageOptions.Convertions.AuthorizePage();

五、ERP认证和授权

    ERP页面的部分使用传统webform的认证体系,而提供的接口部分使用了自定义HttpModule的方式,由于很多ERP演化升级过程中被动接受了很多身份认证方式的接入,所以原本实现授权的HttoModule的逻辑变得异常复杂,而这一次在改造Core的过程中进行了全面的改造后面会进行讲述。同样授权也是一样,将原本实现在Page基类中的复杂的判断逻辑进行了改造。

    ERP在pub接口的身份认证方面需要实现对如下不同的方式:

  • Pub接口

  • 内部集成

  • 接口管家

  • Mip集成

  • OA集成

    之前讲过ERP是通过元数据来驱动的页面逻辑,权限实际是通过通过元数据配置到界面元素上的权限点来进行标识。通过常用的用户-角色-权限的模型模型来关联用户和权限点,然后通过在Page的基类中通过拿到用户的权限来判断是否有当前URL的访问权限,在按钮渲染的时候来获取是否有该按钮的权限点来控制是否显示。

    在这次的改造过程中我们进行了如下改造:

  1. Mvc Core CookiesAuthentication中间件来实现页面的身份认证。

  2. 扩展MVC Core 的 AuthenticationScheme来实现接口的身份认证。

  3. 扩展MVC Core 的 Authentization Policy +Requirement来实现页面的身份授权。

下面通过这三部分进行讲述。

5.1、CookiesAuthentication身份认证

    MVC Core 自带的基于Cookies的身份认证已经能满足我们的需求,只需要稍微进行一下配置即可。通过一张图我们了解下整个的身份认证流程,使用代码参考本章开头Asp.Net Core对认证和授权进行分析的部分。

    因为只是使用来说已经比较简单这里不做过多的描述。这里有一个点需要注意,在Cookie的认证中如果是负载均衡的场景,两个不同进程的引用需要都可以进行客户端Cookies的解密。那么就需要共享加解密的key,这里我们使用MVC Core自带的基于Entity Framework Core 的密钥持久化方式,通过存放到数据库来实现密钥的共享。这部分内容可以参考:https://docs.microsoft.com/zh-cn/aspnet/core/security/data-protection/implementation/key-storage-providers?view=aspnetcore-3.1&tabs=visual-studio。

5.2、Pub接口的身份认证

    除了页面访问以及页面ajax请求这些事基于Cookies的身份认证之外,在提供的接口用了其他的认证方式,这次将所有接口的认证方式进行了抽象,统一使用OpenApi的Scheme进行认证,而实际各种不同的认证方式我们是通过实入AuthenticationMiddleware中调用的IAuthenticationRequestHandler来实现的。首先我们看一下执行的流程:

    之前有一篇关于Mvc Core的Controller改造的文章,其中将pub接口的发现和特性路由扩展进行了扩展,这里我们在扩展的地方添加OpenApi类型Scheme的元数据。

    因为我们的接口统一是使用/pub/开头的所以我们选择使用扩展IAuthentication RequestHandler来实现,这样在判断是否要进行认证的时候需要判断url是否以pub开头即可,下面是类图:

    其中核心就是MockUserAuthHandler,因为在Erp的接口中都会用到用户相关的信息,所以我们所有的pub接口操作实际的身份认证都是模拟了用户的认证,这里将这个概念显式的移动到基类之中,我们通过如下代码进行接入:

public static AuthenticationBuilder AddOpenApiAuth(this AuthenticationBuilder builder)
{builder.AddScheme(AppConst.ApiSchemeName, AppConst.ApiSchemeName,null);return builder.AddScheme<ApiAuthOptions, OpenApiAuthHandler>(AppConst.OpenApi, AppConst.OpenApi, null).AddScheme<ApiAuthOptions, AccessTokenAuthHandler>(AppConst.AccessToken, AppConst.AccessToken, null).AddScheme<ApiAuthOptions, OAuthV1AuthHandler>(AppConst.OAuthV1, AppConst.OAuthV1, null).AddScheme<ApiAuthOptions, OAuthV2AuthHandler>(AppConst.OAuthV2, AppConst.OAuthV2, null).AddScheme<ApiAuthOptions, InternalIntegrationAuthHandler>(AppConst.InternalIntegration, AppConst.InternalIntegration, null);
}

    这里我们添加了众多的Scheme只是为了在AuthenticationMiddleware中处理请求并进行模拟用户登录,并未有实际的Action上有此Sheme,在Action上使用的只有AppConst.ApiSchemeName(“OpenApiScheme”)。

    在Cookies的认证的流程中因为是在登录过程中将认证信息写到Cookies中,而其他请求只需要进行Cookies解析即可获得用户信息。而pub接口请求是在一个用户请求过程中完成整个过程,实际是通过解析Header的特定内容,然后跟保存在Erp中的认证信息进行对比来确定身份,最后在模拟用户之后,进行登录操作来完成整个身份认证的流程。

    这里我们采用扩展IAuthentication RequestHandler的方式有如下考虑:

  1. 如果采用IAuthenticationHandler + Sheme,Core的标准是按照不同的请求使用不同Scheme无法支持,而实际来说都是通过pub接口进行区分,并没有区分到具体的请求。

  2. 目前ERP的认证方式跟行业标准方案不同,以后如果接入标准方案,增加Scheme更加容易扩展并兼容现有方案。

  3. IAuthenticationRequestHandler官方给出是远程认证时候使用,在以后前后端分离加上微服务的升级过程中,只需要修改这部分请求中认证信息发送给远程服务器认证即可,更加符合官方推荐使用的风格。

  综合来说采取IAuthentication RequestHandler而不采用IAuthenticationHandler + Sheme 方式,还是基于官方给出的推荐使用风格和Erp扩展需求综合考虑而来。

5.3、Razor页面授权

    在页面改造篇我们讲述了页面改造的过程,我们知道RazorPage实际是类似CodeBehind的模式,通过PageModel的OnGet方法,每个页面都有对应的PageModel,所以我们这里定义的BasePageModel基类如下:

//其他Attribute
[Authorize(Policy = AppConst.UserAuth,AuthenticationSchemes = “Cookies”)]
public abstract class BasePageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
{protected readonly MapPageContext _mapPageContext;protected BasePageModel(MapPageContext mapPageContext){_mapPageContext = mapPageContext;VerifyApplication.CheckStatus();}
}

    这里我们使用Cookies的Scheme进行授权,特别的是我们还增加了AuthentizationPolicy的定义,通过定义的Policy加上PolicyProvider来实现不同的Policy的切换,Policy的使用代码如下:

public static IMvcBuilder AddFrontend(this IMvcBuilder builder)
{builder.AddRazorPagesOptions(options =>{//…//建模的权限options.Conventions.AuthorizeFolder(“/modeling”, AppConst.ModelingAuth);});//页面权限builder.Services.AddMapAuth();//...
}
//注册
private static void AddMapAuth(this IServiceCollection services)
{services.AddSingleton();services.TryAddEnumerable(ServiceDescriptor.Transient());services.TryAddEnumerable(ServiceDescriptor.Transient());services.TryAddEnumerable(ServiceDescriptor.Transient());
}//Policy实现
internal class MapAuthPolicyProvider : IAuthorizationPolicyProvider{private DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }public MapAuthPolicyProvider(IOptions<AuthorizationOptions> options){FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);}public Task<AuthorizationPolicy> GetPolicyAsync(string policyName){if (policyName.StartsWith(AppConst.ModelingAuth, StringComparison.OrdinalIgnoreCase)){var policy = new AuthorizationPolicyBuilder();policy.AddRequirements(new ModelingRequirement());return Task.FromResult(policy.Build());}if (policyName.StartsWith(AppConst.AppAuth, StringComparison.OrdinalIgnoreCase)){var policy = new AuthorizationPolicyBuilder();policy.AddRequirements(new AppAuthRequirement());return Task.FromResult(policy.Build());}if (policyName.StartsWith(AppConst.UserAuth, StringComparison.OrdinalIgnoreCase)){var policy = new AuthorizationPolicyBuilder();policy.AddRequirements(new UserAuthRequirement());return Task.FromResult(policy.Build());}//返回默认的认证return FallbackPolicyProvider.GetPolicyAsync(policyName);}public Task<AuthorizationPolicy> GetDefaultPolicyAsync(){return FallbackPolicyProvider.GetDefaultPolicyAsync();}
}

    通过上述代码实现了不同策略使用不同的Requirement进行授权的校验,至于授权校验逻辑就是常见的用户权限判断。下面是整体的执行流程:

六、总结

    Core认证和授权改造主要是要对Core的认证和授权的逻辑要清晰,这里核心就是去扒源码,由于之前对Asp.Net MVC的了解,直接就从AuthorizeFilter入手很快就可以找到切入点,然后了解到整个Core认证和授权的核心。

    权限这部分的改造不仅仅只是代码的迁移,也是风格的一个改造,将原来认证和授权的大泥球的设计,通过Core提供的Scheme+Requirement的扩展进行结合的重新设计。

------ END ------

作者简介

熊同学: 研发工程师,目前负责ERP运行平台的设计与开发工作。

也许您还想看

【复杂系统迁移 .NET Core平台系列】之迁移项目工程

【复杂系统迁移 .NET Core平台系列】之界面层

【复杂系统迁移 .NET Core平台系列】之静态文件

招商城科走进武汉研发中心,现场编码解锁平台内核技术

如何解决大批量数据保存的性能问题

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

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

相关文章

《C++ Primer》13.1.3节练习

练习13.9: 析构函数完成与构造函数相反的工作&#xff1a;释放对象使用的资源&#xff0c;销毁非静态数据成员。从语法上看&#xff0c;它是类的一个成员函数&#xff0c;名字是波浪号接类名&#xff0c;没有返回值&#xff0c;也不接受参数。 当一个类没有定义析构函数时&…

.NET Core开发实战(第30课:领域事件:提升业务内聚,实现模块解耦)--学习笔记...

30 | 领域事件&#xff1a;提升业务内聚&#xff0c;实现模块解耦我们在领域的抽象层定义了领域事件和领域事件处理的接口IDomainEventnamespace GeekTime.Domain {public interface IDomainEvent : INotification{} }这是一个空接口&#xff0c;它只是标记出来某一个对象是否是…

《C++ Primer》8.1.2节练习

练习8.1: #include <iostream> #include <stdexcept> using namespace std;istream &f(istream &in) {int v;while (in >> v, !in.eof()) {if (in.bad())throw runtime_error("IO流错误");if (in.fail()) {cerr << "数据错误&…

.NET 5 Preview 1的深度解读和跟进

这几天微软.NET 团队发布了.NET 5 Preview 1, 如约而至。很兴奋&#xff0c;因为.NET Core和.NET Framework终于实现了大一统&#xff0c;同时也很期待&#xff0c;期待.NET 5能给我们带来哪些好的新特性。让我们先把时间拨回到2019年...一、2019年.NET 5的提前剧透去年2019年 …

程序员羽化之路--假如需要一百万个对象

点击上方蓝字关注我们菜菜哥&#xff0c;救命呀又被产品经理砍了&#xff1f;这次搞不好真要被砍了&#xff0c;线上一个用户系统内存溢出了&#xff0c;占用内存太高了用户基数大&#xff0c;内存占用高正常高的不太正常了&#xff0c;我觉得可能和我的设计有关那说说你的用户…

WTM 3.5发布,VUE来了!

千呼万唤中&#xff0c;WTM的Vue前后端分离版本终于和大家见面了&#xff0c;我曾经跟群里1000多位用户保证过Vue版本会在春天到来&#xff0c;吹过的牛逼总算是圆上了。卧槽&#xff0c;NB啊!我等到花都谢了风太大&#xff0c;吹瞎了朕的双眼我是谁&#xff0c;我在哪儿&#…

java 第三方序列化,11.既然有第三方的序列化方式,说明java官方提供的序列化方式应该有一些很明显或者很致命的缺点……...

序列化是什么&#xff1a;把一个java对象转化为二进制对象&#xff0c;并保存到硬盘&#xff0c;或在网络上传输。反序列化就是把序列化的二进制对象读到内存中。 作用&#xff1a;1、减少内存占用或网络传输。比如web容器中的session&#xff0c;当session数量过大比如10W连接…

2020年,我来盘点下微服务架构技术栈

2020年了&#xff0c;很多小伙伴儿对微服务还比较陌生&#xff0c;说起来很多人可能不敢相信&#xff0c;其实微服务这个概念早在2012年就提出来了&#xff0c;经过了这些年的发展&#xff0c;现在已经成为企业非常主流的架构选项了。今天&#xff0c;我就来带大家一起探讨下微…

2.5w字长文爆肝 C++动态内存与智能指针一篇搞懂!太顶了!!!

动态内存与智能指针1.动态内存与智能指针2.shared_ptr类2.1.make_shared函数2.2.shared_ptr的拷贝和赋值2.3.shared_ptr自动销毁所管理的对象2.4. shared_ptr会自动释放相关联的内存2.5.使用了动态生存期的资源的类2.6.定义StrBlob类2.7. StrBlob构造函数2.8.元素访问成员函数2…

ASP.NET Core应用的7种依赖注入方式

ASP.NET Core框架中的很多核心对象都是通过依赖注入方式提供的&#xff0c;如用来对应用进行初始化的Startup对象、中间件对象&#xff0c;以及ASP.NET Core MVC应用中的Controller对象和View对象等&#xff0c;所以我们可以在定义它们的时候采用注入的形式来消费已经注册的服务…

ASP.NET Core 3.x - 为什么采用新的 Endpoint Routing 路由系统

Endpoint Routing 路由系统ASP.NET Core 3.x 使用了一套叫做 Endpoint Routing 的路由系统。这套路由系统在ASP.NET Core 2.2 的时候就开始露面了。这套Endpoint Routing路由系统提供了更强大的功能和灵活性&#xff0c;以便能更好的处理请求。早期ASP.NET Core的路由系统我们先…

《C++ Primer》10.1节练习

练习10.1: #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {vector<int>vi;int val;vi.push_back(45);vi.push_back(45);vi.push_back(45);vi.push_back(45);for (int i 1; i < 45; i) {vi.push_ba…

Asp.Net Core AuthorizeAttribute 和AuthorizeFilter 跟进及源码解读

一、前言IdentityServer4已经分享了一些应用实战的文章&#xff0c;从架构到授权中心的落地应用&#xff0c;也伴随着对IdentityServer4掌握了一些使用规则&#xff0c;但是很多原理性东西还是一知半解&#xff0c;故我这里持续性来带大家一起来解读它的相关源代码&#xff0c;…

1张手稿图讲明白 Kubernetes 是怎么运行的

注意&#xff1a;如果您已经知道Kubernetes的工作原理&#xff0c;那么您可能会对我之前的博文感兴趣&#xff0c;请停止使用具有管理员权限的kubeconfigKubernetes是最初由Google设计的开源工具&#xff0c;现在由 Cloud Native Computing Foundation&#xff08;CNCF&#xf…

就喜欢用vSphere部署K8s集群,不全是因为自动化!

通过努力&#xff0c;我们有了一个完整配置的工作负载域&#xff0c;其中包括一个NSX-T Edge部署。现在&#xff0c;我们准备继续使用Kubernetes 部署vSphere。通过VMware Cloud Foundation 4.0中的SDDC Manager&#xff0c;我们确保NSX-T Edge可用&#xff0c;并且还确保Workl…

同源策略_如何支持跨域

欢迎大家阅读《朝夕Net社区技术专刊》我们致力于.NetCore的推广和落地&#xff0c;为更好的帮助大家学习&#xff0c;方便分享干货&#xff0c;特创此刊&#xff01;很高兴你能成为忠实读者&#xff0c;文末福利不要错过哦&#xff01;01PARTCoreWebApi的调用1.在Core MVC下建立…

企业数字化转型解决方案

2020年国务院常务会议明确指出&#xff0c;依托工业互联网促进传统产业加快上线上云。此前&#xff0c;工信部也在全国工业和信息化工作会议上表示&#xff0c;2020年要实施“5G工业互联网”512工程。和5G、人工智能等同列的“新基建”&#xff0c;工业互联网成为数字时代的基础…

网站 asp和php的用途,asp和php都有什么功能?

ASP是什么&#xff1f;有什么功能&#xff1f;ASP.NET是微软开发&#xff0c;建立动态的&#xff0c;强大的&#xff0c;智能的、可扩展的网站和网际网络应用的全功能的程序语言如C或VB.NET #。它包括一个强大的安全评估的亮点&#xff0c;以及一个组织的小工具&#xff0c;可以…

ASP.NET Core 3.x - Endpoint Routing 路由体系的内部机制

Endpoint是什么&#xff1f;Endpoint简单的可以理解为这样的一些类&#xff0c;它们包含一个请求的委托&#xff08;Request Delegate&#xff09;和其它的一些元数据&#xff0c;使用这些东西&#xff0c;Endpoint类可以生成一个响应。而在MVC的上下文中&#xff0c;这个请求委…

java获取主机信息大全,网络编程:Java获取网络主机信息

java.net.InetAddress类表示互联网协议 (IP) 地址。有两个子类&#xff1a;Inet4Address&#xff0c; Inet6Address通过 InetAddress可以方便获取一个域名下的IP&#xff0c;也可以获取一个IP的主机名。下面是例子&#xff0c;通过程序查看51cto主机的IP信息&#xff0c;51cto是…