.NET 6.0中使用Identity框架實現JWT身份認證與授權

原文作者:Sarathlal Saseendran

原文鏈接:https://www.c-sharpcorner.com/article/jwt-authentication-and-authorization-in-net-6-0-with-identity-framework/

翻譯:沙漠盡頭的狼(谷歌翻譯加持)

介紹

微軟于 2021 年 11 月發布了 .NET 6.0。我已經在 C# Corner[1] 上寫了幾篇關于 JWT 身份認證的文章。由于 .NET 6.0 進行了一些重大更改,因此我決定寫一篇關于使用 .NET 6.0 版本進行 JWT 身份認證的文章。我們將使用微軟 Identity 框架來存儲用戶和角色信息。

Authentication(身份認證)是驗證用戶憑據的過程,而Authorization(授權)是檢查用戶訪問應用程序中特定模塊的權限的過程。在本文中,我們將了解如何通過實現 JWT 身份認證來保護 ASP.NET Core Web API 應用程序。我們還將了解如何在 ASP.NET Core 中使用授權來提供對應用程序各種功能的訪問。我們將用戶憑據存儲在 SQL Server 數據庫中(注:您可以使用MySQL、PostgreSQL等其他關系型數據庫),我們將使用 EF Core 框架和 Identity 框架進行數據庫操作。

JSON Web Token (JWT) 是一個開放標準 (RFC 7519),它定義了一種緊湊且自包含的方式,使用JSON 對象用于在各方之間安全地傳輸信息。此信息可以驗證和信任,因為它是數字簽名的。JWT 可以使用密鑰(使用HMAC算法)或使用RSAECDSA的公鑰/私鑰對進行簽名。

在其緊湊的形式中,JSON Web Tokens 由三部分組成,由點 (.) 分隔,它們是:

  • Header(標題 )

  • Payload(有效載荷 )

  • Signature(簽名 )

因此,JWT 格式通常如下所示:

xxxx.yyyy.zzzz

有關 JSON Web token的更多詳細信息,請參閱下面的鏈接。

https://jwt.io/introduction/[2]

使用 Visual Studio 2022 創建 ASP.NET Core Web API

我們需要 Visual Studio 2022 來創建 .NET 6.0 應用程序。我們可以從 Visual Studio 2022 中選擇 ASP.NET Core Web API 模板。

bc961391dac4cb8b9a4b59700cab15ab.png

我們可以為我們的項目起一個合適的名稱并選擇 .NET 6.0 框架。

7adb697a4a16783722b7a4e1dcf4cb86.png

我們的新項目將在隨后創建。

我們必須將以下 4 個庫安裝到新項目中。

  • Microsoft.EntityFrameworkCore.SqlServer

  • Microsoft.EntityFrameworkCore.Tools

  • Microsoft.AspNetCore.Identity.EntityFrameworkCore

  • Microsoft.AspNetCore.Authentication.JwtBearer

您可以使用 NuGet 包管理器來安裝上述包。

我們可以使用以下值更改 appsettings.json。它具有用于 JWT 身份認證的數據庫連接詳細信息和其他詳細信息。

appsettings.json

{"Logging":?{"LogLevel":?{"Default":?"Information","Microsoft.AspNetCore":?"Warning"}},"AllowedHosts":?"*","ConnectionStrings":?{"ConnStr":?"Data?Source=(localdb)\\MSSQLLocalDB;Initial?Catalog=JWTAuthDB;Integrated?Security=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"},"JWT":?{"ValidAudience":?"http://localhost:4200","ValidIssuer":?"http://localhost:5000","Secret":?"JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr"}
}

我們可以創建一個新文件夾 Auth 并在 Auth 文件夾下創建 ApplicationDbContext 類并添加以下代碼。我們將在 Auth 文件夾下添加所有與身份認證相關的類。

ApplicationDbContext.cs

using?Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using?Microsoft.AspNetCore.Identity;
using?Microsoft.EntityFrameworkCore;namespace?IdentityDemo.Auth
{public?class?ApplicationDbContext?:?IdentityDbContext<IdentityUser>{public?ApplicationDbContext(DbContextOptions<ApplicationDbContext>?options)?:?base(options){}protected?override?void?OnModelCreating(ModelBuilder?builder){base.OnModelCreating(builder);}}
}

創建一個靜態類 UserRoles 并添加以下值。

UserRoles.cs

namespace?IdentityDemo.Auth
{public?static?class?UserRoles{public?const?string?Admin?=?"Admin";public?const?string?User?=?"User";}
}

我們添加了兩個常量值 AdminUser 作為角色。您可以根據需要添加任意數量的角色。

創建類 RegisterModel, 新用戶注冊時使用。

RegisterModel.cs

using System.ComponentModel.DataAnnotations;namespace IdentityDemo.Auth
{public class RegisterModel{[Required(ErrorMessage = "用戶名不能為空")] public string? Username { get; set; }[EmailAddress][Required(ErrorMessage = "郵件不能為空")]public string? Email { get; set; }[Required(ErrorMessage = "密碼不能為空")] public string? Password { get; set; }}
}

創建類 LoginModel 用于用戶登錄。

LoginModel.cs

using?System.ComponentModel.DataAnnotations;namespace?IdentityDemo.Auth
{public?class?LoginModel{[Required(ErrorMessage?=?"用戶名不能為空")]?public?string??Username?{?get;?set;?}[Required(ErrorMessage?=?"密碼不能為空")]?public?string??Password?{?get;?set;?}}
}

我們可以創建一個 Response 類,用于在用戶注冊和用戶登錄后返回響應值。如果請求失敗,它也會返回錯誤消息。

Response.cs

namespace?IdentityDemo.Auth
{public?class?Response{public?string??Status?{?get;?set;?}public?string??Message?{?get;?set;?}}
}

我們可以在 Controllers 文件夾中創建一個 API 控制器 AuthenticateController 并添加以下代碼。

AuthenticateController.cs

using?IdentityDemo.Auth;
using?Microsoft.AspNetCore.Identity;
using?Microsoft.AspNetCore.Mvc;
using?Microsoft.IdentityModel.Tokens;
using?System.IdentityModel.Tokens.Jwt;
using?System.Security.Claims;
using?System.Text;namespace?IdentityDemo.Controllers
{[Route("api/[controller]")][ApiController]public?class?AuthenticateController?:?ControllerBase{private?readonly?UserManager<IdentityUser>?_userManager;private?readonly?RoleManager<IdentityRole>?_roleManager;private?readonly?IConfiguration?_configuration;public?AuthenticateController(UserManager<IdentityUser>?userManager,RoleManager<IdentityRole>?roleManager,IConfiguration?configuration){_userManager?=?userManager;_roleManager?=?roleManager;_configuration?=?configuration;}[HttpPost][Route("login")]public?async?Task<IActionResult>?Login([FromBody]?LoginModel?model){var?user?=?await?_userManager.FindByNameAsync(model.Username);if?(user?!=?null?&&?await?_userManager.CheckPasswordAsync(user,?model.Password)){var?userRoles?=?await?_userManager.GetRolesAsync(user);var?authClaims?=?new?List<Claim>{new?Claim(ClaimTypes.Name,?user.UserName),new?Claim(JwtRegisteredClaimNames.Jti,?Guid.NewGuid().ToString()),};foreach?(var?userRole?in?userRoles){authClaims.Add(new?Claim(ClaimTypes.Role,?userRole));}var?token?=?GetToken(authClaims);return?Ok(new{token?=?new?JwtSecurityTokenHandler().WriteToken(token),expiration?=?token.ValidTo});}return?Unauthorized();}[HttpPost][Route("register")]public?async?Task<IActionResult>?Register([FromBody]?RegisterModel?model){var?userExists?=?await?_userManager.FindByNameAsync(model.Username);if?(userExists?!=?null)return?StatusCode(StatusCodes.Status500InternalServerError,new?Response?{?Status?=?"Error",?Message?=?"用戶已經存在!"?});IdentityUser?user?=?new(){Email?=?model.Email,SecurityStamp?=?Guid.NewGuid().ToString(),UserName?=?model.Username};var?result?=?await?_userManager.CreateAsync(user,?model.Password);if?(!result.Succeeded)return?StatusCode(StatusCodes.Status500InternalServerError,new?Response{Status?=?"Error",?Message?=?"創建用戶失敗!請檢查后再重試。"});return?Ok(new?Response?{?Status?=?"Success",?Message?=?"新增用戶成功!"?});}[HttpPost][Route("register-admin")]public?async?Task<IActionResult>?RegisterAdmin([FromBody]?RegisterModel?model){var?userExists?=?await?_userManager.FindByNameAsync(model.Username);if?(userExists?!=?null)return?StatusCode(StatusCodes.Status500InternalServerError,new?Response?{?Status?=?"Error",?Message?=?"用戶已經存在!"?});IdentityUser?user?=?new(){Email?=?model.Email,SecurityStamp?=?Guid.NewGuid().ToString(),UserName?=?model.Username};var?result?=?await?_userManager.CreateAsync(user,?model.Password);if?(!result.Succeeded)return?StatusCode(StatusCodes.Status500InternalServerError,new?Response{Status?=?"Error",?Message?=?"創建用戶失敗!請檢查后再重試。"});if?(!await?_roleManager.RoleExistsAsync(UserRoles.Admin))await?_roleManager.CreateAsync(new?IdentityRole(UserRoles.Admin));if?(!await?_roleManager.RoleExistsAsync(UserRoles.User))await?_roleManager.CreateAsync(new?IdentityRole(UserRoles.User));if?(await?_roleManager.RoleExistsAsync(UserRoles.Admin)){await?_userManager.AddToRoleAsync(user,?UserRoles.Admin);}if?(await?_roleManager.RoleExistsAsync(UserRoles.Admin)){await?_userManager.AddToRoleAsync(user,?UserRoles.User);}return?Ok(new?Response?{?Status?=?"Success",?Message?=?"新增用戶成功!"?});}private?JwtSecurityToken?GetToken(List<Claim>?authClaims){var?authSigningKey?=?new?SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));var?token?=?new?JwtSecurityToken(issuer:?_configuration["JWT:ValidIssuer"],audience:?_configuration["JWT:ValidAudience"],expires:?DateTime.Now.AddHours(3),claims:?authClaims,signingCredentials:?new?SigningCredentials(authSigningKey,?SecurityAlgorithms.HmacSha256));return?token;}}
}

我們在控制器類中添加了三個方法 loginregisterregister-admin``。registerregister-admin 幾乎相同,但 register-admin 方法將用于創建具有 Admin 角色的用戶。在 login 方法中,我們在成功登錄后返回了一個 JWT token

.NET 6.0 中,微軟刪除了 Startup 類(注:您可以恢復繼續使用這種方式),只保留了 Program 類。我們必須在 Program 類中定義所有依賴注入和其他配置。

Program.cs

using?IdentityDemo.Auth;
using?Microsoft.AspNetCore.Authentication.JwtBearer;
using?Microsoft.AspNetCore.Identity;
using?Microsoft.EntityFrameworkCore;
using?Microsoft.IdentityModel.Tokens;
using?System.Text;var?builder?=?WebApplication.CreateBuilder(args);
ConfigurationManager?configuration?=?builder.Configuration;//?Add?services?to?the?container.//?For?Entity?Framework
builder.Services.AddDbContext<ApplicationDbContext>(options?=>?options.UseSqlServer(configuration.GetConnectionString("ConnStr")));//?For?Identity
builder.Services.AddIdentity<IdentityUser,?IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();//?Adding?Authentication
builder.Services.AddAuthentication(options?=>
{options.DefaultAuthenticateScheme?=?JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme?=?JwtBearerDefaults.AuthenticationScheme;options.DefaultScheme?=?JwtBearerDefaults.AuthenticationScheme;
})//?Adding?Jwt?Bearer
.AddJwtBearer(options?=>
{options.SaveToken?=?true;options.RequireHttpsMetadata?=?false;options.TokenValidationParameters?=?new?TokenValidationParameters(){ValidateIssuer?=?true,ValidateAudience?=?true,ValidAudience?=?configuration["JWT:ValidAudience"],ValidIssuer?=?configuration["JWT:ValidIssuer"],IssuerSigningKey?=?new?SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"]))};
});builder.Services.AddControllers();
//?Learn?more?about?configuring?Swagger/OpenAPI?at?https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();var?app?=?builder.Build();//?Configure?the?HTTP?request?pipeline.
if?(app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseHttpsRedirection();//?Authentication?&?Authorization
app.UseAuthentication();
app.UseAuthorization();app.MapControllers();app.Run();

我們必須在運行應用程序之前創建所需的數據庫和表。由于我們使用的是實體框架(EF Core),我們可以使用下面的數據庫遷移命令和包管理器控制臺來創建一個遷移腳本:

add-migration Initial

5e1a44390a52469d51b4addf2f097926.png

使用以下命令創建數據庫和表:

update-database

ea3c42f0e6df2fe0ffc760eaa636aaff.png

如果您使用 SQL Server 對象資源管理器檢查數據庫,您可以看到在數據庫內部創建了以下數據庫表:

57bbd81e46be058cc701d154d2da5055.png

在數據庫遷移過程中,為 UserRoleClaims 創建了 7 張表。這是用于 Identity框架。

ASP.NET Core Identity 是一個會員系統,允許您向應用程序添加登錄功能。用戶可以創建帳戶并使用用戶名和密碼登錄,也可以使用外部登錄提供程序,例如 Facebook、Google、Microsoft Account、Twitter 等。

您可以將 ASP.NET Core Identity 配置為使用 SQL Server 數據庫來存儲用戶名、密碼和配置文件數據。或者,你可以使用自己的持久化存儲將數據存儲在另一個其他持久化存儲中,例如 Azure 表存儲。

我們可以在 WeatherForecast 控制器中添加 Authorize 屬性。

ba4813d89b33077d4a1cf0372bef5b82.png

我們可以運行應用程序并嘗試從 Postman 工具訪問WeatherForecastController中的 get 方法。

fb4579b75f27c9aaec7139a7a6e5b092.png

我們收到了 401 未經授權的錯誤。因為,我們已經為整個控制器添加了 Authorize 屬性。我們必須通過請求頭提供一個有效的token來訪問這個控制器和控制器內的方法。

我們可以在AuthenticateController中使用注冊方法創建一個新用戶。

2e4d4afd3b3f3588413503143a88ba69.png

我們以原始 JSON 格式提供了輸入數據。

我們可以使用上述用戶憑據登錄并獲取有效的 JWT token

e572ea70143336de777f239cd436ba04.png

使用上述憑據成功登錄后,我們收到了一個token

我們可以使用https://jwt.io[3]站點 解碼token并查看聲明和其他信息。

7b2dc7d9fba0d4e3b994117f1a0f26dd.png

我們可以在授權選項卡中將上述token值作為Bearer token傳遞,并再次調用WeatherForecastControllerget 方法。

755a11582653962a3880b088634cc093.png

這一次,我們成功地接收到了來自控制器的值。

我們可以使用基于角色的授權來更改WeatherForecastController

e00661373377ea8b3e14a2f193365d97.png

現在,只有具有管理員(Admin)角色的用戶才能訪問此控制器和方法。

我們可以嘗試在 Postman 工具中再次使用相同的token訪問WeatherForecastController。

34848ce34189851d216824237e907422.png

我們現在收到了 403 拒絕錯誤而不是 401。即使我們傳遞了一個有效的token,我們也沒有足夠的權限來訪問控制器。要訪問此控制器,用戶必須具有Admin角色權限。當前用戶是普通用戶,沒有任何Admin角色權限。

我們可以創建一個具有Admin角色權限的新用戶。我們已經在AuthenticateController中有一個方法register-admin用于相同的目的。

ba5cdbb8ecf87701fed39c4abafcb4d7.png

我們可以使用這些新的用戶憑據登錄并獲得一個新的token。如果您對token進行解碼,您可以看到角色已添加到token中。

39239632a156392704fa0cfded9c67fe.png

我們可以使用這個token而不是舊token來訪問WeatherForecastController

0f5d7e093f07c112aa661f6e2a2e9fb9.png

現在我們已經成功地從WeatherForecastController中獲取了數據。

結論

在這篇文章中,我們了解了如何在 .NET 6.0 ASP.NET Core Web API 應用程序中創建 JSON Web token,并使用此token進行身份認證和授權。我們創建了兩個用戶,一個沒有任何角色,一個有Admin角色。我們在控制器級別應用了身份認證和授權,并看到了這兩個用戶的不同行為。

  • 本文源碼:IdentityDemo[4]

參考資料

[1]

C# Corner: https://www.c-sharpcorner.com/

[2]

https://jwt.io/introduction/: https://jwt.io/introduction/

[3]

https://jwt.io: https://jwt.io

[4]

IdentityDemo: https://github.com/dotnet9/ASP.NET-Core-Test/tree/master/src/IdentityDem

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284354.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284354.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284354.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

adb devices 里面有很多 emulator-XXXX的解決方法

2019獨角獸企業重金招聘Python工程師標準>>> adb kill-server 轉載于:https://my.oschina.net/sfshine/blog/700354

MQ(Message Queue)簡介

一、何為MQ&#xff1f; MQ全稱為Message Queue, 消息隊列&#xff08;MQ&#xff09;是一種應用程序對應用程序的通信方法。應用程序通過讀寫出入隊列的消息&#xff08;針對應用程序的數據&#xff09;來通信&#xff0c;而無需專用連接來鏈接它們。消息傳遞指的是程序之間通…

【GlobalMapper精品教程】015:矢量面圖層的創建及數字化操作

本文講解在Globalmapper中文23.0中創建矢量面狀數據(政區數據),并進行面狀數據采集及編輯的詳細操作流程,數據為配套案例數據包中的data015.rar。 參考閱讀: ArcGIS實驗教程——實驗三:矢量數據采集與編輯(矢量化) 文章目錄 一、認識工具條1. 數字化(創建)工具條2. 選…

Blazor University (39)JavaScript 互操作 —— 更新 document title

原文鏈接&#xff1a;https://blazor-university.com/javascript-interop/calling-javascript-from-dotnet/updating-the-document-title/更新 document title源代碼[1]在創建 Blazor 布局[2]部分中&#xff0c;我們看到了 Blazor 應用程序如何存在于 HTML&#xff08;或 cshtm…

IIS 日志文件位置

IIS 6 Log files location IIS 6中日志文件的位置%windir%\System32\LogFilesIIS 7 Log files location IIS的日志文件的位置%SystemDrive%\inetpub\logs\LogFiles用戶每打開一次網頁&#xff0c;iis 都會記錄用戶IP、訪問的網頁地址、訪問時間、訪問狀態等信息&#xff0c;這些…

APP測試流程和測試點

1 APP測試基本流程 1.1流程圖 1.2測試周期 測試周期可按項目的開發周期來確定測試時間&#xff0c;一般測試時間為兩三周&#xff08;即15個工作日&#xff09;&#xff0c;根據項目情況以及版本質量可適當縮短或延長測試時間。正式測試前先向主管確認項目排期。 1.3測試資源 測…

39所強基計劃試點高校已全部公布招生簡章

截至目前(4月8日下午) 39所強基計劃試點高校 已全部公布招生簡章 各高校招生要求是什么&#xff1f; 招生專業有哪些&#xff1f; 什么時候報名&#xff1f; 一起來看 北京大學 招生對象及報名條件 各省&#xff08;區、市&#xff09;符合2022年全國普通高等學校招生統…

【ArcGIS錯誤異常100問】之001:License服務無法啟動權威解決辦法

測試環境&#xff1a; 操作系統&#xff1a;Windows10ArcGIS版本&#xff1a;10.X結果&#xff1a;通過測試 文章目錄1. 錯誤提示2. 問題分析3. 解決辦法3.1 關閉Windows Defender3.2 關閉系統防火墻3.3 刪除邁克菲&#xff08;McAfee&#xff09;殺毒軟件3.4 在系統服務中啟動…

Appium wait等待的三種方法

1、sleep()方法Thread.sleep&#xff08;60000&#xff09;強制等待60s2、隱式等待implicitlyWait()driver.manage().timeouts().implicitlyWait(30,TimeUnit.SECONDS);全局等待30s不管元素是否已經加載1) 當使用了隱式等待執行測試的時候&#xff0c;如果WebDriver沒有在DOM中…

ASP.NET Core 技術內幕與項目實戰讀后感

前幾天拿到了楊中科老師的新書《ASP.NET Core 技術內幕與項目實戰》&#xff0c;迫不及待的“兩”口氣讀完了。用一句話來總結&#xff0c;這是一本寫給.NET開發者的非常實用的接地氣的好書&#xff0c;感覺有必要自發為這本書宣傳一波。楊老師在 .NET 開發者社區中的知名度非常…

avalon2學習教程15指令總結

avalon的指令在上一節已經全部介紹完畢&#xff0c;當然有的語焉不詳&#xff0c;如ms-js。本節主要總結我對這方面的思考與探索。 MVVM的成功很大一語分是來自于其指令&#xff0c;或叫綁定。讓操作視圖的功能交由形形式式的指令來代勞。VM&#xff0c;成了一個大管家。它只一…

【ArcGIS錯誤異常100問】之002:Error 000735 簡化容差:值是必需的(簡化線、簡化面工具)

測試環境&#xff1a; 操作系統&#xff1a;windows7ArcGIS版本&#xff1a;10.2結果&#xff1a;通過測試 文章目錄1. 錯誤提示2. 問題分析3. 解決辦法4. 問題驗證1. 錯誤提示 在ArcGIS中使用簡化面或者簡化線工具時&#xff0c;點擊確定會提示Error 000735&#xff1a;簡化容…

mybatis中mysql轉義講解

本文為博主原創&#xff0c;未經允許不得轉載&#xff1a; 在mybatis中寫sql的時候&#xff0c;遇到特殊字符在加載解析的時候&#xff0c;會進行轉義&#xff0c;所以在mybatis中 寫sql語句的時候&#xff0c;遇到特殊字符進行轉義處理。 需要注意的是&#xff0c;轉義的字符為…

用Python執行js文件代碼并獲取返回結果

js代碼&#xff08;myjs.js&#xff09;&#xff1a; /** Title: This is a file for ……* Author: JackieZheng* Date: 2022-04-12 09:24:13* LastEditTime: 2022-04-12 09:40:55* LastEditors: Please set LastEditors* Description:* FilePath: myjs.js*/function hello(…

.NET桌面開發的一些思考

在22日&#xff0c;我在公眾號上發布了一條短文字&#xff0c;內容如下&#xff1a;其實在.NET開發大軍中&#xff0c;還有一股力量&#xff0c;那就是桌面程序的開發者們。他們很少發聲&#xff0c;可能技術成熟&#xff0c;可能太企業化了&#xff0c;也可能我沒關注到。最近…

【ArcGIS錯誤異常100問】之003:屬性表中文亂碼解決辦法總結

測試環境&#xff1a; 操作系統&#xff1a;windows7ArcGIS版本&#xff1a;10.X、Pro結果&#xff1a;通過測試 文章目錄1. 錯誤提示2. 原因分析3. 解決方法4. 問題驗證1. 錯誤提示 如圖所示&#xff0c;安裝完ArcGIS Pro后&#xff0c;由于計算機系統和應用軟件字符編碼的問…

大型網站架構演化(二)——應用服務和數據服務分離

隨著網站業務的發展&#xff0c;一臺服務器逐漸不能滿足需求&#xff1a;越來越多的用戶訪問導致性能越來越差&#xff0c;越來越多的數據導致存儲空間不足。這時就需要將應用和數據分離。應用和數據分離后整個網站使用三臺服務器&#xff1a;應用服務器、文件服務器和數據庫服…

再不自動化就晚啦!優云教你4步打造基于CentOS的產品鏡像

隨著Linux程序的增多&#xff0c;軟件的安裝過程中經常出現如下問題&#xff1a; 1、硬件配置類似或者相同時&#xff0c;批量安裝系統和軟件&#xff0c;希望實現自動化安裝&#xff0c;減少安裝時間和人為出錯。 2、工程實施人員在不同客戶現場進行系統和軟件安裝(硬件配置不…

【ArcGIS錯誤異常100問】之004:ArcGIS表轉Excel超了65535限制解決辦法

測試環境&#xff1a; 操作系統&#xff1a;windows7ArcGIS版本&#xff1a;10.2 文章目錄1. 錯誤提示2. 原因分析3. 解決方法1. 錯誤提示 如下圖&#xff0c;當矢量shp圖斑數目過多&#xff0c;文件超過了65535條記錄時&#xff0c;利用ArcGIS的表轉Excel工具處理成Excel文件…

[轉]硬核 | Redis 布隆(Bloom Filter)過濾器原理與實戰

在Redis 緩存擊穿&#xff08;失效&#xff09;、緩存穿透、緩存雪崩怎么解決&#xff1f;中我們說到可以使用布隆過濾器避免「緩存穿透」。 碼哥&#xff0c;布隆過濾器還能在哪些場景使用呀&#xff1f; 比如我們使用「碼哥跳動」開發的「明日頭條」APP 看新聞&#xff0c;如…