IdentityServer4系列 | 混合模式

一、前言

在上一篇关于授权码模式中, 已经介绍了关于授权码的基本内容,认识到这是一个拥有更为安全的机制,但这个仍然存在局限,虽然在文中我们说到通过后端的方式去获取token,这种由web服务器和授权服务器直接通信,不需要经过用户的浏览器或者其他的地方,但是在这种模式中,授权码仍然是通过前端通道进行传递的,而且在访问资源的中,也会将访问令牌暴露给外界,就仍存在安全隐患。

快速回顾一下之前初识基础知识点中提到的,IdentityServer4OpenID Connect+ OAuth2.0 相结合的认证框架,用户身份认证和API的授权访问,两个结合一块,实现了认证和授权的结合。

在几篇关于授权模式篇章中,其中我们也使用了关于OpenID Connect的简化流程,在简化流程中,所有令牌(身份令牌、访问令牌)都通过浏览器传输,这对于**身份令牌(IdentityToken)「来说是没有问题的,但是如果是」访问令牌(AccessToken)**直接通过浏览器传输,就增加了一定的安全问题。因为访问令牌比身份令牌更敏感,在非必须的情况下,我们不希望将它们暴露给外界。

所以我们就会考虑增加安全性,在OpenID Connect 包含一个名为“Hybrid(混合)”的流程,它为我们提供了两全其美的优势,身份令牌通过浏览器传输,因此客户端可以在进行任何更多工作之前对其进行验证。如果验证成功,客户端会通过令牌服务的以获取访问令牌。

二、初识

在认识混合模式(Hybrid Flow)时候,可以发现这里跟上一篇的授权码模式有很多相似的地方,具体可以查看授权码模式

查看使用OpenIDConnect时的安全性和隐私注意事项相关资料可以发现,

「授权码模式」「混合模式」的流程步骤分别如下:

Authorization Code Flow Steps

The Authorization Code Flow goes through the following steps.

  1. Client prepares an Authentication Request containing the desired request parameters.

  2. Client sends the request to the Authorization Server.

  3. Authorization Server Authenticates the End-User.

  4. Authorization Server obtains End-User Consent/Authorization.

  5. Authorization Server sends the End-User back to the Client with an Authorization Code.

  6. Client requests a response using the Authorization Code at the Token Endpoint.

  7. Client receives a response that contains an ID Token and Access Token in the response body.

  8. Client validates the ID token and retrieves the End-User's Subject Identifier.

Hybrid Flow Steps

The Hybrid Flow follows the following steps:

  1. Client prepares an Authentication Request containing the desired request parameters.

  2. Client sends the request to the Authorization Server.

  3. Authorization Server Authenticates the End-User.

  4. Authorization Server obtains End-User Consent/Authorization.

  5. Authorization Server sends the End-User back to the Client with an Authorization Code and, depending on the Response Type, one or more additional parameters.

  6. Client requests a response using the Authorization Code at the Token Endpoint.

  7. Client receives a response that contains an ID Token and Access Token in the response body.

  8. Client validates the ID Token and retrieves the End-User's Subject Identifier.

由以上对比发现,codehybrid一样都有8个步骤,大部分步骤也是相同的。最主要的区别在于第5步。

「在授权码模式中,成功响应身份验证」

 HTTP/1.1 302 FoundLocation: https://client.example.org/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj

「在混合模式中,成功响应身份验证:」

HTTP/1.1 302 FoundLocation: https://client.example.org/cb#code=SplxlOBeZQQYbYS6WxSbIA&id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso&state=af0ifjsldkj

其中多了一个id_token

在使用这些模式的时候,成功的身份验证响应,存在指定的差异。这些授权端点的结果以不同的的依据返回。其中code是一定会返回的,access_token和id_token的返回依据 response_type 参数决定。

混合模式根据response_type的不同,authorization endpoint返回可以分为三种情况。

1. response_type = code + id_token ,即包含Access Token和ID Token

2. response_type = code + token ,即包含Authorization Code和Access Token

3. response_type = code + id_token + token,即包含Authorization Code、identity Token和Access Token

三、实践

接着我们进行一些简单的实践,因为有了前面授权码模式代码的经验,编写混合模式也是很简单的。

(这里重复之前的代码,防止被爬抓后内容的缺失不完整)

在示例实践中,我们将创建一个授权访问服务,定义一个MVC客户端,MVC客户端通过「IdentityServer」上请求访问令牌,并使用它来访问API。

3.1 搭建 Authorization Server 服务

搭建认证授权服务

3.1.1 安装Nuget包

IdentityServer4 程序包

3.1.2 配置内容

建立配置内容文件Config.cs

public static class Config
{public static IEnumerable<IdentityResource> IdentityResources =>new IdentityResource[]{new IdentityResources.OpenId(),new IdentityResources.Profile(),};public static IEnumerable<ApiScope> ApiScopes =>new ApiScope[]{new ApiScope("hybrid_scope1")};public static IEnumerable<ApiResource> ApiResources =>new ApiResource[]{new ApiResource("api1","api1"){Scopes={ "hybrid_scope1" },UserClaims={JwtClaimTypes.Role},  //添加Cliam 角色类型ApiSecrets={new Secret("apipwd".Sha256())}}};public static IEnumerable<Client> Clients =>new Client[]{new Client{ClientId = "hybrid_client",ClientName = "hybrid Auth",ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },AllowedGrantTypes = GrantTypes.Hybrid,RedirectUris ={"http://localhost:5002/signin-oidc", //跳转登录到的客户端的地址},// RedirectUris = {"http://localhost:5002/auth.html" }, //跳转登出到的客户端的地址PostLogoutRedirectUris ={"http://localhost:5002/signout-callback-oidc",},ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },AllowedScopes = {IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile,"hybrid_scope1"},//允许将token通过浏览器传递AllowAccessTokensViaBrowser=true,// 是否需要同意授权 (默认是false)RequireConsent=true}};
}

RedirectUris : 登录成功回调处理的客户端地址,处理回调返回的数据,可以有多个。

PostLogoutRedirectUris :跳转登出到的客户端的地址。

这两个都是配置的客户端的地址,且是identityserver4组件里面封装好的地址,作用分别是登录,注销的回调

因为是「混合」授权的方式,所以我们通过代码的方式来创建几个测试用户。

新建测试用户文件TestUsers.cs

    public class TestUsers{public static List<TestUser> Users{get{var address = new{street_address = "One Hacker Way",locality = "Heidelberg",postal_code = 69118,country = "Germany"};return new List<TestUser>{new TestUser{SubjectId = "1",Username = "i3yuan",Password = "123456",Claims ={new Claim(JwtClaimTypes.Name, "i3yuan Smith"),new Claim(JwtClaimTypes.GivenName, "i3yuan"),new Claim(JwtClaimTypes.FamilyName, "Smith"),new Claim(JwtClaimTypes.Email, "i3yuan@email.com"),new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),new Claim(JwtClaimTypes.WebSite, "http://i3yuan.top"),new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(address), IdentityServerConstants.ClaimValueTypes.Json)}}};}}}

返回一个TestUser的集合。

通过以上添加好配置和测试用户后,我们需要将用户注册到IdentityServer4服务中,接下来继续介绍。

3.1.3 注册服务

在startup.cs中ConfigureServices方法添加如下代码:

        public void ConfigureServices(IServiceCollection services){var builder = services.AddIdentityServer().AddTestUsers(TestUsers.Users); //添加测试用户// in-memory, code configbuilder.AddInMemoryIdentityResources(Config.IdentityResources);builder.AddInMemoryApiScopes(Config.ApiScopes);builder.AddInMemoryApiResources(Config.ApiResources);builder.AddInMemoryClients(Config.Clients);// not recommended for production - you need to store your key material somewhere securebuilder.AddDeveloperSigningCredential();services.ConfigureNonBreakingSameSiteCookies();}

3.1.4 配置管道

在startup.cs中Configure方法添加如下代码:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseStaticFiles();app.UseRouting();app.UseCookiePolicy();app.UseAuthentication();app.UseAuthorization();app.UseIdentityServer();app.UseEndpoints(endpoints =>{endpoints.MapDefaultControllerRoute();}); }

以上内容是快速搭建简易IdentityServer项目服务的方式。

「这搭建 Authorization Server 服务跟上一篇授权码模式有何不同之处呢?」

  1. 在Config中配置客户端(client)中定义了一个AllowedGrantTypes的属性,这个属性决定了Client可以被哪种模式被访问,「GrantTypes.Hybrid」「混合模式」。所以在本文中我们需要添加一个Client用于支持授权码模式(「Hybrid」)。

3.2 搭建API资源

实现对API资源进行保护

3.2.1 快速搭建一个API项目

3.2.2 安装Nuget包

IdentityServer4.AccessTokenValidation 包

3.2.3 注册服务

在startup.cs中ConfigureServices方法添加如下代码:

    public void ConfigureServices(IServiceCollection services){services.AddControllersWithViews();services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)services.AddAuthentication("Bearer").AddIdentityServerAuthentication(options =>{options.Authority = "http://localhost:5001";options.RequireHttpsMetadata = false;options.ApiName = "api1";options.ApiSecret = "apipwd"; //对应ApiResources中的密钥});}

AddAuthentication把Bearer配置成默认模式,将身份认证服务添加到DI中。

AddIdentityServerAuthentication把IdentityServer的access token添加到DI中,供身份认证服务使用。

3.2.4 配置管道

在startup.cs中Configure方法添加如下代码:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}    app.UseRouting();app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapDefaultControllerRoute();});}

UseAuthentication将身份验证中间件添加到管道中;

UseAuthorization 将启动授权中间件添加到管道中,以便在每次调用主机时执行身份验证授权功能。

3.2.5 添加API资源接口

[Route("api/[Controller]")]
[ApiController]
public class IdentityController:ControllerBase
{[HttpGet("getUserClaims")][Authorize]public IActionResult GetUserClaims(){return new JsonResult(from c in User.Claims select new { c.Type, c.Value });}
}

在IdentityController 控制器中添加 [Authorize] , 在进行请求资源的时候,需进行认证授权通过后,才能进行访问。

3.3 搭建MVC 客户端

实现对客户端认证授权访问资源

3.3.1 快速搭建一个MVC项目

3.3.2 安装Nuget包

IdentityServer4.AccessTokenValidation 包

3.3.3 注册服务

要将对 OpenID Connect 身份认证的支持添加到MVC应用程序中。

在startup.cs中ConfigureServices方法添加如下代码:

    public void ConfigureServices(IServiceCollection services){services.AddControllersWithViews();services.AddAuthorization();services.AddAuthentication(options =>{options.DefaultScheme = "Cookies";options.DefaultChallengeScheme = "oidc";}).AddCookie("Cookies")  //使用Cookie作为验证用户的首选方式.AddOpenIdConnect("oidc", options =>{options.Authority = "http://localhost:5001";  //授权服务器地址options.RequireHttpsMetadata = false;  //暂时不用httpsoptions.ClientId = "hybrid_client";options.ClientSecret = "511536EF-F270-4058-80CA-1C89C192F69A";options.ResponseType = "code id_token"; //代表options.Scope.Add("hybrid_scope1"); //添加授权资源options.SaveTokens = true; //表示把获取的Token存到Cookie中options.GetClaimsFromUserInfoEndpoint = true;});services.ConfigureNonBreakingSameSiteCookies();}
  1. AddAuthentication注入添加认证授权,当需要用户登录时,使用 cookie 来本地登录用户(通过“Cookies”作为DefaultScheme),并将 DefaultChallengeScheme 设置为“oidc”,

  2. 使用 AddCookie 添加可以处理 cookie 的处理程序。

  3. AddOpenIdConnect用于配置执行 OpenID Connect 协议的处理程序和相关参数。Authority表明之前搭建的 IdentityServer 授权服务地址。然后我们通过ClientIdClientSecret,识别这个客户端。SaveTokens用于保存从IdentityServer获取的token至cookie,「ture」标识ASP.NETCore将会自动存储身份认证session的access和refresh token。

  4. 我们在配置ResponseType时需要使用Hybrid定义的三种情况之一,具体代码如上所述。

3.3.4 配置管道

然后要确保认证服务执行对每个请求的验证,加入UseAuthenticationUseAuthorizationConfigure中,在startup.cs中Configure方法添加如下代码:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}else{app.UseExceptionHandler("/Home/Error");}app.UseStaticFiles();app.UseRouting();app.UseCookiePolicy();app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");});}

UseAuthentication将身份验证中间件添加到管道中;

UseAuthorization 将启动授权中间件添加到管道中,以便在每次调用主机时执行身份验证授权功能。

3.3.5 添加授权

在HomeController控制器并添加[Authorize]特性到其中一个方法。在进行请求的时候,需进行认证授权通过后,才能进行访问。

        [Authorize]public IActionResult Privacy(){ViewData["Message"] = "Secure page.";return View();}

还要修改主视图以显示用户的Claim以及cookie属性。

@using Microsoft.AspNetCore.Authentication<h2>Claims</h2><dl>@foreach (var claim in User.Claims){<dt>@claim.Type</dt><dd>@claim.Value</dd>}
</dl><h2>Properties</h2><dl>@foreach (var prop in (await Context.AuthenticateAsync()).Properties.Items){<dt>@prop.Key</dt><dd>@prop.Value</dd>}
</dl>

访问 Privacy 页面,跳转到认证服务地址,进行账号密码登录,Logout 用于用户的注销操作。

3.3.6 添加资源访问

HomeController控制器添加对API资源访问的接口方法。在进行请求的时候,访问API受保护资源。

        /// <summary>/// 测试请求API资源(api1)/// </summary>/// <returns></returns>public async Task<IActionResult> getApi(){var client = new HttpClient();var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);if (string.IsNullOrEmpty(accessToken)){return Json(new { msg = "accesstoken 获取失败" });}client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);var httpResponse = await client.GetAsync("http://localhost:5003/api/identity/GetUserClaims"); var result = await httpResponse.Content.ReadAsStringAsync();if (!httpResponse.IsSuccessStatusCode){return Json(new { msg = "请求 api1 失败。", error = result });}return Json(new{msg = "成功",data = JsonConvert.DeserializeObject(result)});}

测试这里通过获取accessToken之后,设置client请求头的认证,访问API资源受保护的地址,获取资源。

3.4 效果

我们通过对比授权码模式与混合模式 可以发现,在大部分步骤是相同的,但也存在一些差异。

在整个过程中,我们使用抓取请求,可以看到在Authorization Endpoint中两者的区别如下:

「授权码模式:」

「混合模式:」

在Authorization EndPoint返回的Id_Token和Token EndPoint返回的id_Token中,可以看到两次值是可能不相同的,但是其中包含的用户信息都是一样的。

在使用Hybrid时我们看到授权终结点返回的Id Token中包含at_hash(Access Token的哈希值)和s_hash(State的哈希值),规范中定义了以下的一些检验规则。

  1. 两个id_token中的 iss 和 sub 必须相同。

  2. 如果任何一个 id token 中包含关于终端用户的声明,两个令牌中提供的值必须相同。

  3. 关于验证事件的声明必须都提供。

  4. at_hash 和 s_hash 声明可能会从 token 端点返回的令牌中忽略,即使从 authorize 端点返回的令牌中已经声明。

四、问题

4.1 设置RequirePkce

在指定基于授权码的令牌是否需要验证密钥,默认为true。

「解决方法:」

修改Config中的RequirePkce为false即可。这样服务端便不在需要客户端提供code challeng。

 RequirePkce = false,//v4.x需要配置这个

4.2 设置ResponseType

在上文中提到的MVC客户端中配置ResponseType时可以使用Hybrid定义的三种情况。

而当设置为"code token", "code id_token token"中的一种,即只要包含token,都会报如下错误:

解决方法:

授权服务端中的Config中增加允许将token通过浏览器传递

AllowAccessTokensViaBrowser = true,

五、总结

  1. 由于令牌都通过浏览器传输,为了提高更好的安全性,我们不想暴露访问令牌, OpenID Connect包含一个名为“Hybrid(混合)”的流程,它可以让身份令牌(id_token)通过前端浏览器通道传输,因此客户端可以在做更多的工作之前验证它。如果验证成功,客户端会打开令牌服务的后端服务器通道来检索访问令牌(access_token)。

  2. 在后续会对这方面进行介绍继续说明,数据库持久化问题,以及如何应用在API资源服务器中和配置在客户端中,会进一步说明。

  3. 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。

  4. 项目地址

https://github.com/i3yuan/Yuan.IdentityServer4.Demo/tree/main/DiffAuthMode/HybridFlowAuthentication

六、附加

「OpenID Connect资料」

「Grant Types 类型」

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

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

相关文章

3m格式的文件怎么转换成mp3_一招就能让PDF与其他格式文件相互转换,这样的大招你值得拥有...

大家都知道&#xff0c;现在不少的大佬比起用Word、Excel等等这些格式文件&#xff0c;它们更喜欢使用PDF文件。而我们不管是将Word、Excel等文件转换成PDF&#xff0c;还是将PDF转换成其他格式文件&#xff0c;都是一件麻烦事&#xff0c;更别说在手机上操作这一切了。别担心&…

如何使用 C# 中的 Tuple

开局一张图&#xff0c;首先声明的是 Tuple 不是什么新鲜概念&#xff0c;在编程语言 F#&#xff0c;Python 中早就有这个了&#xff0c;Tuple 是一种 有序的&#xff0c;有限不可变的&#xff0c;支持混杂类型的固定个数的 一种数据结构&#xff0c;有些朋友可能就想问了&…

中设置colorbar_【值得收藏】如何画出学术论文中需要的各种精美插图,看这一篇就够了!...

本文整理自知乎问答&#xff0c;仅用于学术分享&#xff0c;著作权归作者所有。如有侵权&#xff0c;请联系后台作删文处理。方法一作者&#xff5c;冯昱尧https://www.zhihu.com/question/21664179/answer/18928725强烈推荐 Python 的绘图模块 matplotlib: python plotting 。…

GraphQL:Descriptor Attributes

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述&#xff0c;使得客户端能够准确地获得它需要的数据&#xff0c;而且没有任何冗余&#xff0c;也让 API 更容易地随着时间推移而演进&#xff0c…

idea怎么把代码放到git_在IDEA中如何初始化Git,把项目推送到Git上

在IDEA中如何初始化Git&#xff0c;把项目推送到Git上登录Gitee(码云)账号&#xff0c;新建仓库先按如下步骤简单新建一个仓库&#xff1a;创建成功后&#xff0c;会出现下图中所示的原始文件&#xff1a;在IDEA上的Terminal中进行操作注意&#xff1a;可能有些朋友刚打开Termi…

大会线上同步直播, 来不到现场也可以线上看直播,以及参会秘籍

紧急提醒&#xff1a;还有1天&#xff01;2020.NET开发者大会就要开幕啦&#xff01;你都做好参会准备没有&#xff1f;特殊时期&#xff0c;为方便小伙伴们顺利参会&#xff0c;小编特意整理了这篇大会参会攻略&#xff0c;大到各种日程安排、小到签到、出行、防疫等&#xff…

大曾幽默打油诗_这才是真正的幽默打油诗,逗人一笑,又引人深思!

阅读本文前&#xff0c;请您先点击上面的蓝色字体“点点星光”&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到文章了。每天都有分享。完全是免费订阅&#xff0c;请放心关注来源&#xff1a;诗词天地大曾 &#xff0c;曾初良&#xff0c;也乐斋主&#xff0c…

编程去除背景绿幕抠图,基于.NET+OpenCVSharp

摘要&#xff1a;本文介绍了一种使用OpenCVSharp对摄像头中的绿幕视频进行实时“抠人像、替换背景”的方式&#xff0c;对于项目中的算法进行了分析。本文中给出了简化OpenCVSharp中Mat、MatExpr等托管资源释放的方法。本文还介绍了“高效摄像头播放控件”以及和OpenCVSharp的性…

.NET 云原生架构师训练营(模块二 基础巩固 依赖注入)--学习笔记

2.2.1 核心模块--依赖注入什么是依赖注入.NET Core DI 生命周期服务设计服务范围检查ASP.NET Core 依赖注入&#xff1a;https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?viewaspnetcore-5.0什么是依赖注入Dependency injection 依赖注入Inv…

vue ref 绑定的事件需要移除吗_Vue易遗忘的基础复习(二)

数据请求Vue-resource请求在Vue2.0之后已经被舍弃2. fetch请求因为传统 Ajax &#xff08;指 XMLHttpRequest&#xff09;存在一些令人头疼的问题&#xff1a;配置和调用方式非常混乱&#xff0c;而且基于事件的异步模型写起来也没有现代的 Promise&#xff0c;generator/yield…

如何在 ASP.NET Core 中使用 API 分析器

ASP.NET Core 2.2 引入了 API 分析器&#xff0c;它有利于提高 API 的文档化&#xff0c;API分析器 可以应用在任何带有 ApiController 特性的 Controller 上&#xff0c;本篇就和大家一起讨论下。安装 API 分析器 如果你使用的是 ASP.NET Core 2.2 的话&#xff0c;用 Visual …

.net mysql字符串截取_【MySQL】字符串截取之SUBSTRING_INDEX和【MySQL】字符串四则运算...

substring_index(str,delim,count)str:要处理的字符串delim:分隔符count:计数例子&#xff1a;strwww.google.com1.count是正数&#xff0c;那么就是从左往右数&#xff0c;第N个分隔符的左边的全部内容SELECT SUBSTRING_INDEX(www.google.com,.,1);结果是&#xff1a;wwwSELEC…

用C#+Selenium+ChromeDriver 爬取网页,完美模拟真实的用户浏览行为

背景Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。而对于爬虫来说&#xff0c;使用Selenium操控浏览器来爬取网上的数据那么肯定是爬虫中的杀手武器。这里&#xff0c;我将介绍selenium 谷歌浏览器的一般使…

ASP.NET Core ActionFilter引发的一个EF异常

最近在使用ASP.NET Core的时候出现了一个奇怪的问题。在一个Controller上使用了一个ActionFilter之后经常出现EF报错。InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guarante…

BCVP开发者说第5期:QuartzCore.Blazor

沉静岁月&#xff0c;淡忘流年1项目简介QuartzCore.BlazorQuartzCore.Blazor 是一个基于 .Net5 开发的轻量级 Quartz 作业配置中心&#xff0c;实践应用 Ant Design Blazor 和 FreeSql 两个技术&#xff0c; 对这两个技术感兴趣的小伙伴可以加我一起学习讨论哦&#xff0c;对有…

mysql update返回_MySQL中,当update修改数据与原数据相同时会再次执行吗?

本文同步Java知音社区&#xff0c;专注于Java作者&#xff1a;powdbahttps://yq.aliyun.com/articles/694162一、背景本文主要测试MySQL执行update语句时&#xff0c;针对与原数据&#xff08;即未修改&#xff09;相同的update语句会在MySQL内部重新执行吗&#xff1f;二、测试…

.NET 云原生架构师训练营(模块二 基础巩固 日志)--学习笔记

2.2.2 核心模块--日志ILogger 的使用日志的 ID日志的分类日志的级别LoggerProvider日志的最佳实践.NET Core 和 ASP.NET Core 中的日志记录&#xff1a;https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/logging/?viewaspnetcore-5.0ILogger 的使用在 Get 方法中添…

mysql数据库设计三大范式_了解数据库设计三大范式

数据库设计范式什么是范式&#xff1a;简言之就是&#xff0c;数据库设计对数据的存储性能&#xff0c;还有开发人员对数据的操作都有莫大的关系。所以建立科学的&#xff0c;规范的的数据库是需要满足一些规范的来优化数据数据存储方式。在关系型数据库中这些规范就可以称为范…

使用BeetleX网关部署第三方Web服务

BeetleX的http/ws网关在早期版本可以启动和管理第三方Web服务进程&#xff0c;在最新的1.5版本中引入了文件管理功能&#xff0c;通过这一功能可以对第三方Web服务进行发布管理。加入文件管理后BeetleX的新版本网关服务可以理解为一个简单化的IIS&#xff0c;但它的不同之处是可…

2020.NET开发者大会大会线上同步直播,以及参会秘籍

2020.NET开发者大会马上就要开幕啦&#xff01;你都做好参会准备没有&#xff1f;本届峰会线上分享将在思否和CSDN两个媒体平台同步进行&#xff0c;大家可以选择适合自己的方式在线参与互动哦&#xff01;访问下方链接&#xff0c;可以直接加入直播&#xff1a;思否直播观看地…