ASP.NET Core Web API 實現 JWT 身份驗證

在ASP.NET Core WebApi中使用標識框架(Identity)-CSDN博客

因為一般需要和標識框架一起使用,建議先查看標識框架用法

一.為什么需要JWT

我們的系統需要實現認證,即服務端需要知道登錄進來的客戶端的身份,管理員有管理員的權限,普通用戶有普通用戶的權限.

但服務端是基于HTTP協議的,該協議本質上是無狀態,兩次請求本質上是獨立的,也就是說該協議無法幫我們實現認證.

1、傳統的 Session 認證機制

早期認證的實現方式是Session,流程大概如下:

(1)用戶登錄,服務端驗證用戶名密碼成功后,生成一個唯一的 SessionId。

(2)這個 SessionId 存在服務端內存(或者數據庫、Redis)里,對應一個用戶狀態。

(3)服務端通過 Set-Cookie 把 SessionId 寫入瀏覽器 Cookie。

(4)瀏覽器后續請求自動攜帶 Cookie,服務端用這個 SessionId 找到用戶信息。

Session 的缺點:

問題說明
服務器內存壓力每登錄一個用戶,服務器都要保存一份 Session 數據,用戶多了就容易撐爆內存
不適合分布式多臺服務器集群部署時,Session 要么共享存儲(如 Redis),要么做 Session 粘性路由,增加系統復雜度
跨域難處理前后端分離、跨域 API 調用時,Cookie 不好用或者需要復雜的 CORS 配置
狀態管理復雜如果 Session 丟失、超時、清理,用戶體驗會很差,需要額外處理

2、JWT 的出現:無狀態化認證?

隨著微服務、云原生、前后端分離等架構興起,開發者開始追求一種 「無狀態」且「輕量級」 的認證方案,JWT 應運而生。

3、JWT 對比 Session 的核心區別

對比點SessionJWT
狀態管理服務端有狀態,需要存儲每個用戶 Session完全無狀態,Token 自包含用戶信息
存儲位置服務端內存/數據庫客戶端自行保存(通常存在本地存儲或 Cookie)
跨服務需要共享 Session 或做負載均衡粘性天然支持多服務,無需 Session 同步
擴展性橫向擴展困難服務端可任意擴容
性能每次請求都查找 Session不需要查 Session,Token 自解密驗證

4、JWT 的工作流程概覽(無狀態認證)?

(1)用戶登錄,后端生成 JWT 返回給前端。

(2)前端保存好 JWT

(3)每次 API 請求,前端把 JWT 放到 Authorization: Bearer 頭里。

(4)后端中間件解析 JWT,驗簽,通過后即可認為該用戶已登錄。

服務端只負責「驗簽 + 解密」,不保存任何 Session 狀態。

5、JWT 的優點

優點說明
跨服務、跨平臺多服務架構天然支持,移動 App、Web 前端、第三方系統都可以用同一個 Token
減少服務器壓力服務端無需保存登錄狀態
性能高每次只需做一次 Token 驗證,無需 Session 查詢
易與 CDN、API 網關等集成請求攜帶 Token,網關層即可完成鑒權
標準化基于開放標準 RFC7519,廣泛支持,工具鏈成熟

6、為什么現在很多新項目都選擇 JWT??

  • 適合微服務

  • 適合前后端分離

  • 適合跨平臺 App

  • 適合無狀態、彈性伸縮的云架構

7、JWT 取代 Session,不是因為它絕對更好,而是因為它更「適應當代架構」

JWT 并不是完美無缺,它也有一些缺點,比如:

缺點說明
Token 無法主動失效如果用戶登出或者權限變更,老 Token 依然有效(可通過 Token 黑名單、Token 版本號等方式繞過)
容易被盜用如果 Token 泄露,別人拿到 Token 就可以冒充用戶
Token 較長JWT 體積大,不適合非常高頻短連接場景

二.什么是 JWT?

JWT,全稱 JSON Web Token,是一種開放標準(RFC 7519),用于在不同系統之間安全地傳輸信息。它是一種基于 JSON 格式、經過數字簽名的數據令牌,主要應用于 身份認證信息交換 場景。


1.JWT 的核心用途

  1. 身份認證(Authentication)
    用戶登錄成功后,服務器生成一個包含用戶身份信息的 JWT,返回給客戶端。客戶端后續每次請求,都帶上這個 Token,服務器通過驗證 Token,確認用戶身份,無需重復登錄。

  2. 信息交換(Information Exchange)
    系統之間可以通過 JWT 安全地交換一些加密或不可篡改的聲明信息。

2.JWT 的結構:三段式組成

一個典型的 JWT 長這樣(這是被算法處理過的):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwicm9sZSI6IkFkbWluIn0.NhJzHfJZKIo0FPWqGk92OukUjD0YPgXVyknzZoAW_2Y
?

被點號分隔成三段:?

(1) Header(頭部)
指定 Token 的類型(通常是 JWT)以及簽名所用的算法,比如 HS256

{"alg": "HS256","typ": "JWT"
}

(2) Payload(負載)
放具體的聲明信息(Claims),比如用戶 ID、用戶名、角色、過期時間等。

{"userName": "admin","role": "Admin","exp": 1719820800
}

(3) Signature(簽名)
防止篡改。由 Header、Payload 和一個 Secret 密鑰(只有服務端知道),通過指定算法生成。

簽名生成方式(以 HMAC-SHA256 為例):

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret
)

三.控制臺使用

1.環境搭建

先創建一個控制臺程序生成JWT,需要安裝JWT讀寫的NuGet包

System.IdentityModel.Tokens.Jwt

?2.生成JWT

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
static void Main(string[] args)
{// 創建用戶的 Claims 列表// Claim就代表一條用戶信息。Claim有兩個主要的屬性:Type和Value,它們都是string類型的,Type代表用戶信息的類型,Value代表用戶信息的值。// Type屬性可以是預定義的類型,如ClaimTypes.Name、ClaimTypes.Role等,也可以是自定義的類型。var claims = new List<Claim>();// 用戶唯一標識,比如用戶ID,這里用"6"做示例claims.Add(new Claim(ClaimTypes.NameIdentifier, "6"));// 用戶姓名,這里是 "ZhangSan"claims.Add(new Claim(ClaimTypes.Name, "ZhangSan"));// 用戶角色,注意:可以有多個角色聲明claims.Add(new Claim(ClaimTypes.Role, "User"));claims.Add(new Claim(ClaimTypes.Role, "Admin"));// 自定義 Claim,比如擴展字段,這里自定義了一個 "jz" 字段claims.Add(new Claim("jz", "112233"));// 定義密鑰字符串,生產環境一般放在配置文件,不要硬編碼string key = "kjdfsjffd^kjfkfkds#dsffdsdsfd@fdsufdsfo33300";// 設置 Token 的過期時間,這里是 1 天后過期DateTime expires = DateTime.Now.AddDays(1);// 把密鑰字符串轉成字節數組byte[] secBytes = Encoding.UTF8.GetBytes(key);// 根據密鑰生成對稱加密安全密鑰對象var secKey = new SymmetricSecurityKey(secBytes);// 指定簽名算法,這里使用 HMAC-SHA256var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);// 創建 JWT Token 對象,包括:claims、過期時間、簽名憑據var tokenDescriptor = new JwtSecurityToken(claims: claims,                   // 載荷:用戶身份信息expires: expires,                 // 有效期signingCredentials: credentials   // 簽名信息);// 把 JwtSecurityToken 對象序列化成最終的 Token 字符串string jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);// 輸出 TokenConsole.WriteLine(jwt);
}
eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjYiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiWmhhbmdTYW4iLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiVXNlciIsIkFkbWluIl0sImp6IjoiMTEyMjMzIiwiZXhwIjoxNzUwOTg5ODMwfQ.7sl9Y18uxGU-Xd9Ly3rfXKnKidBJ_ZZjPyZOwnTR_0c

3.JWT解析

Header 和 Payload 是明文的,只是做了 Base64Url 編碼,不是加密

比如一個原始 Payload:

{"userName": "admin","role": "Admin","exp": 1719820800
}

?Base64Url 編碼后就是一串字母數字:

eyJ1c2VyTmFtZSI6ImFkbWluIiwicm9sZSI6IkFkbWluIiwiZXhwIjoxNzE5ODIwODAwfQ

?JWT 三部分都是明文(Header 和 Payload 可直接 Base64Url 解碼),JWT 的重點是防篡改而不是保密

所以不難理解,別人拿到你的JWT就可以冒充你.

jwt在線解密/加密 - JSON中文網json中文網致力于在中國推廣json,json Web Tokens 是目前流行的跨域認證解決方案,json中文網提供jwt解密/加密工具,提供HS256、HS384和HS512等簽名算法的編碼和校驗。https://www.json.cn/jwt?可以將得到的JWT直接放到jwt解析網站上就能解析出前兩部分的信息.

或者使用下面這個方法

string jwt = Console.ReadLine()!;
string[] segments = jwt.Split('.');
string head = JwtDecode(segments[0]); // 頭部
string payload = JwtDecode(segments[1]); // 負載
Console.WriteLine("--------head--------");
Console.WriteLine(head);
Console.WriteLine("--------payload--------");
Console.WriteLine(payload);string JwtDecode(string s)
{s = s.Replace('-', '+').Replace('_', '/');switch (s.Length % 4){case 2:s += "==";break;case 3:s += "=";break;}var bytes = Convert.FromBase64String(s); // 解碼return Encoding.UTF8.GetString(bytes);
}

?可以看到信息被解析出來了,由于JWT會被發送到客戶端,而負載中的內容是以明文形式保存的,因此一定不要把不能被客戶端知道的信息放到負載中。

JWT的編碼和解碼規則都是公開的,而且負載部分的Claim信息也是明文的,因此惡意攻擊者可以對負載部分中的用戶ID等信息進行修改,從而冒充其他用戶的身份來訪問服務器上的資源。因此,服務器端需要對簽名部分進行校驗,從而檢查JWT是否被篡改了。

// 從控制臺讀取用戶輸入的 JWT 字符串
string jwt = Console.ReadLine()!;  // 注意:加了 "!" 是為了告訴編譯器:這里不會是 null// 定義密鑰字符串(要與生成 JWT 時用的密鑰保持一致,否則驗證會失敗)
string secKey = "kjdfsjffd^kjfkfkds#dsffdsdsfd@fdsufdsfo33300";// 創建一個 JWT Token 解析器
JwtSecurityTokenHandler tokenHandler = new();// 定義 Token 驗證參數
TokenValidationParameters valParam = new();// 設置簽名驗證的密鑰,必須和生成時一致
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secKey));
valParam.IssuerSigningKey = securityKey;// 不驗證簽發者 (Issuer),這里簡化處理(生產環境可以啟用校驗)
valParam.ValidateIssuer = false;// 不驗證接收者 (Audience),同樣為了簡化
valParam.ValidateAudience = false;// 開始驗證 Token
// ValidateToken 方法會做:
// 1. 驗證簽名
// 2. 驗證 Token 是否過期
// 3. 返回解析后的 ClaimsPrincipal 對象(包含用戶身份信息)
// out 參數會返回原始的 SecurityToken 對象
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwt, valParam, out SecurityToken secToken);// 遍歷解析出來的 Claim 列表,并輸出每個 Claim 的類型和值
foreach (var claim in claimsPrincipal.Claims)
{Console.WriteLine($"{claim.Type}={claim.Value}");
}

如果篡改JWT,程序運行時就會拋出內容為“Signature validation failed”的異常。exp值是過期時間,如果收到過期的JWT,即使簽名校驗成功,ValidateToken方法也會拋出異常


四.WebApi中使用

1.環境準備

 "JWT": {"SigningKey": "kjdfsjffd^kjfkfkds#dsffdsdsfd@fdsufdsfo33300EXTRA","ExpireSeconds": "3600"}
   public class JwtSetting{public string SigningKey { get; set; }public int ExpireSeconds { get; set; }}

我們先在配置系統appsettings.json中配置一個名字為JWT的節點,并在節點下創建SigningKey、ExpireSeconds兩個配置項,分別代表JWT的密鑰和過期時間(單位為秒)。
我們再創建一個對應JWT節點的配置類JwtSetting,類中包含SigningKey、ExpireSeconds這兩個屬性。

安裝Microsoft.AspNetCore.Authentication.JwtBearer包,這個包封裝了簡化ASP.NET Core中使用JWT的操作

?2.注冊服務

// 將配置文件中的 JWT 部分綁定到 JwtSetting 配置類
builder.Services.Configure<JwtSetting>(builder.Configuration.GetSection("JWT"));// 注冊 JWT Bearer 身份認證服務
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(x =>{// 從配置中讀取 JWT 設置對象(比如密鑰等信息)var jwtOpt = builder.Configuration.GetSection("JWT").Get<JwtSetting>();// 把密鑰字符串轉為字節數組byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOpt.SigningKey);// 用密鑰生成對稱安全密鑰對象var secKey = new SymmetricSecurityKey(keyBytes);// 配置 Token 驗證參數x.TokenValidationParameters = new TokenValidationParameters(){// 是否驗證 Token 的簽發者(Issuer),這里關閉ValidateIssuer = false,// 是否驗證 Token 的接收方(Audience),這里關閉ValidateAudience = false,// 是否驗證 Token 的過期時間,生產環境一般要打開,這里關閉是為了開發方便ValidateLifetime = false,// 是否驗證 Token 的簽名,生產環境一定要開ValidateIssuerSigningKey = true,// 用來驗證簽名的密鑰IssuerSigningKey = secKey};});

?本質上就是中間件,別忘了使用.

?3.給登錄用戶發JWT

// 控制器:負責處理用戶登錄請求,并生成 JWT Token
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{private readonly IOptions<JwtSetting> _jwtSetting;           // JWT 配置信息private readonly ILogger<AuthController > _logger;private readonly UserManager<User> _userManager;private readonly RoleManager<Role> _roleManager;public AuthController(ILogger<AuthController > logger, UserManager<User> userManager,RoleManager<Role> roleManager, IOptions<JwtSetting> jwtSetting){_logger = logger;_userManager = userManager;_roleManager = roleManager;_jwtSetting = jwtSetting;}// 登錄接口,接收用戶名密碼,驗證成功后生成 JWT[HttpPost]public async Task<IActionResult> Login(LoginRequest loginRequest){string userName = loginRequest.UserName;string password = loginRequest.Password;// 使用 Identity 框架查找用戶var user = await _userManager.FindByNameAsync(userName);if (user == null){return BadRequest("用戶不存在");}// 判斷用戶是否被鎖定(連續登錄失敗導致)var islocked = await _userManager.IsLockedOutAsync(user);if (islocked){// 用戶鎖定,返回 400,提示鎖定信息return BadRequest("用戶已鎖定!");}// 校驗密碼var success = await _userManager.CheckPasswordAsync(user, password);if (!success){// 密碼錯誤,記錄一次失敗嘗試(用于鎖定機制)var r = await _userManager.AccessFailedAsync(user);if (!r.Succeeded){// 記錄失敗信息失敗,返回錯誤return BadRequest("訪問失敗信息寫入錯誤!");}else{// 普通密碼錯誤返回 400return BadRequest("失敗!");}                }//重置訪問失敗計數await _userManager.ResetAccessFailedCountAsync(user);// 構建 JWT Claims(載荷里的用戶信息)var claims = new List<Claim>{// 用戶唯一標識new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),// 用戶名new Claim(ClaimTypes.Name, user.UserName)};// 查詢用戶角色,并把每個角色加入到 Claimsvar roles = await _userManager.GetRolesAsync(user);foreach (var role in roles){claims.Add(new Claim(ClaimTypes.Role, role));}// 調用封裝好的 Token 構建方法,生成 JWT 字符串string jwtToken = BuildToken(claims, _jwtSetting.Value);// 把 Token 返回給前端return Ok(jwtToken);}/// <summary>/// 根據用戶 Claims 和 JWT 配置,生成 JWT Token 字符串/// </summary>private static string BuildToken(IEnumerable<Claim> claims, JwtSetting _jwtSetting){// 設置 Token 過期時間DateTime expires = DateTime.Now.AddSeconds(_jwtSetting.ExpireSeconds);// 根據配置的密鑰生成安全密鑰對象byte[] keyBytes = Encoding.UTF8.GetBytes(_jwtSetting.SigningKey);var secKey = new SymmetricSecurityKey(keyBytes);// 指定簽名算法,這里用 HMAC-SHA256var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);// 創建 Token 對象,包括過期時間、簽名憑據、Claimsvar tokenDescriptor = new JwtSecurityToken(expires: expires,signingCredentials: credentials,claims: claims);// 序列化成最終 Token 字符串return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);}
}

?4.接口校驗JWT

 [Route("[controller]/[action]")][ApiController][Authorize]  // 表示:訪問此控制器下的所有 Action,都必須登錄并攜帶有效 JWTpublic class UserInfoController : ControllerBase{/// <summary>/// 測試用接口:返回當前登錄用戶的身份信息(從 JWT Claims 解析)/// </summary>[HttpGet]public IActionResult Hello(){// 從 Claims 中獲取用戶IDstring id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;// 獲取用戶名string userName = this.User.FindFirst(ClaimTypes.Name)!.Value;// 獲取用戶擁有的所有角色IEnumerable<Claim> roleClaims = this.User.FindAll(ClaimTypes.Role);// 把角色列表拼接成逗號分隔的字符串string roleNames = string.Join(',', roleClaims.Select(c => c.Value));// 返回身份信息return Ok($"id={id}, userName={userName}, roleNames={roleNames}");}}

添加的[Authorize]表示這個控制器類下所有的操作方法都需要登錄后才能訪問。
ControllerBase中定義的ClaimsPrincipal類型的User屬性代表當前登錄用戶的身份信息,我們可以通過ClaimsPrincipal的Claims屬性獲得當前登錄用戶的所有Claim信息,不過我們一般通過FindFirst方法根據Claim的類型來查找需要的Claim,如果用戶身份信息中含有多個同類型的Claim,我們則可以通過FindAll方法來找到所有Claim。

5.swagger調試

直接訪問401無權限 ,我們需要傳入jwt才能訪問該接口.

ASP.NET Core要求(這也是HTTP的規范)JWT放到名字為Authorization的HTTP請求報文頭中,報文頭的值為“Bearer JWT”。

Swagger中默認沒有提供設置自定義HTTP請求報文頭的方式,因此對于需要傳遞Authorization報文頭的接口,調試起來很麻煩。我們可以通過對OpenAPI進行配置,從而讓Swagger中可以發送Authorization報文頭。

 // 注冊 Swagger 服務,同時配置 JWT 認證支持builder.Services.AddSwaggerGen(c =>{// 定義一個 OpenApiSecurityScheme:告訴 Swagger,這里有一個全局的 Header 參數叫 Authorizationvar scheme = new OpenApiSecurityScheme(){// Swagger UI 上顯示的描述信息,告訴開發者怎么填寫 TokenDescription = "在請求頭中加入 Authorization 字段,例如:'Bearer 12345abcdef'",// 給這個 SecurityScheme 起一個引用ID,后面配置用Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Authorization"},// Scheme 字段,這里用 "oauth2" 字符串(其實可以寫任何字符串,Swagger 不校驗這個)Scheme = "oauth2",// 參數名,Swagger UI 會自動生成這個 Header 字段Name = "Authorization",// 參數的位置:在 HTTP Header 中In = ParameterLocation.Header,// 聲明類型是 API Key(Swagger 把 "Authorization" 這種 Header 參數用 ApiKey 類型)Type = SecuritySchemeType.ApiKey,};// 添加這個 Security 定義,名稱叫 "Authorization",Swagger UI 會顯示一個輸入框c.AddSecurityDefinition("Authorization", scheme);// 創建一個全局安全要求:告訴 Swagger,每個接口默認都要帶這個 SecuritySchemevar requirement = new OpenApiSecurityRequirement();// 給這個 requirement 加上剛才定義的 scheme,值是空列表(Swagger 需要這么寫)requirement[scheme] = new List<string>();// 把這個全局安全要求加到 Swagger 配置里c.AddSecurityRequirement(requirement);});

首先我們要先利用前面的登錄接口獲取一個JWT,然后通過這個按鈕將JWT傳入,此時你就可以訪問那些需要認證的接口了.

?

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

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

相關文章

優化Cereal宏 一行聲明序列化函數

Cereal序列化庫中宏遞歸展開的優化方案及技術解析 未優化&#xff1a;參考nlohmann json設計Cereal宏 一行聲明序列化函數 宏實現 #include <cereal/cereal.hpp>// 強制二次展開 #define CEREAL_EXPAND( x ) x// 獲取宏參數的數量&#xff0c;對應的CEREAL_PASTEn宏NAME…

14-C#的彈出的窗口輸入與輸出

C#的彈出的窗口輸入與輸出 1.文件名輸入 string fileName Interaction.InputBox("輸入保存的文件名", "保存");2.彈窗信息輸出 MessageBox.Show("請選擇輪詢!", "Error", MessageBoxButtons.OK);catch (Exception ex){MessageBox.S…

多模態大語言模型arxiv論文略讀(141)

Mini-InternVL: A Flexible-Transfer Pocket Multimodal Model with 5% Parameters and 90% Performance ?? 論文標題&#xff1a;Mini-InternVL: A Flexible-Transfer Pocket Multimodal Model with 5% Parameters and 90% Performance ?? 論文作者&#xff1a;Zhangwei …

VScode使用usb轉網口遠程開發rk3588

我使用的是魯班貓的板&#xff0c;只有一個網口&#xff0c;需要接雷達&#xff0c;因此另外弄了一個usb轉網口來連接電腦開發。 在使用vscode或MobaXterm連接板子時&#xff0c;使用主機名與用戶名來連接&#xff1a; ssh catlubancat rk那邊就直接插入usb轉網口以及網線&a…

AUTOSAR圖解==>AUTOSAR_AP_EXP_SOVD

AUTOSAR服務導向車輛診斷詳解 面向現代化車輛架構的診斷方案 目錄 1. 引言 1.1 ASAM SOVD簡介1.2 SOVD產生的動機 2. SOVD參考架構 2.1 SOVD網關2.2 診斷管理器2.3 SOVD到UDS轉換2.4 后端連接 3. SOVD用例 3.1 SOVD和UDS的共同用例3.2 SOVD特定用例 3.2.1 訪問權限3.2.2 軟件更…

第八講:STL簡介

1. 什么是STL STL(standard template libaray-標準模板庫)&#xff1a;是C標準庫的重要組成部分&#xff0c;不僅是一個可復的 組件庫&#xff0c;而且是一個包羅數據結構與算法的軟件框架。 2. STL的版本 a. 原始版本 Alexander Stepanov、Meng Lee 在惠普實驗室完成的原始版本…

高彈性、高可靠!騰訊云 TDMQ RabbitMQ Serverless 版全新發布

導語 2025年6月起&#xff0c;騰訊云 TDMQ RabbitMQ 版正式推出 Serverless 版本&#xff0c;該版本基于自研的存算分離架構&#xff0c;兼容 AMQP 0-9-1 協議和開源 RabbitMQ 的各個組件與概念&#xff0c;且能夠規避開源版本固有的不抗消息堆積、腦裂等穩定性缺陷&#xff0…

Linux 內存調優之 BPF 分析用戶態小內存分配

寫在前面 博文內容為 使用 BPF 工具跟蹤 Linux 用戶態小內存分配(brk,sbrk)理解不足小伙伴幫忙指正 ??,生活加油我看遠山,遠山悲憫 持續分享技術干貨,感興趣小伙伴可以關注下 _ brk 內存分配簡單概述 一般來說,應用程序的數據存放于堆內存中,堆內存通過brk(2)系統調用進…

心理測評app心理測試系統框架設計

一、邏輯分析 用戶管理邏輯 新用戶注冊&#xff1a;需要收集用戶的基本信息&#xff0c;如用戶名、密碼、郵箱等&#xff0c;并且要對輸入信息進行合法性校驗&#xff0c;確保信息完整且符合格式要求。同時&#xff0c;為每個新用戶生成唯一的標識符&#xff0c;方便后續數據管…

配置有nvlink的H20A800使用pytorch報錯

背景 裝有nvlink的h20機器上配置好驅動和cuda之后使用pytorch報錯 A800機器同樣 (pytorch2.4) rootxx-dev-H20:~# python Python 3.12.0 | packaged by Anaconda, Inc. | (main, Oct 2 2023, 17:29:18) [GCC 11.2.0] on linux Type “help”, “copyright”, “credits” or …

sql的語句執行過程

第一步&#xff1a;客戶端把語句發給服務器端執行 當我們在客戶端執行SQL語句時&#xff0c;客戶端會把這條SQL語句發送給服務器端&#xff0c;讓服務器端的進程來處理這語句。也就是說&#xff0c;Oracle 客戶端是不會做任何的操作&#xff0c;他的主要任務就是把客戶端產生的…

深度學習-分類

深度學習-分類方式 &#xff08;重點&#xff09;一、按數據類型與處理邏輯分類1. 序列數據&#xff08;時序/順序相關&#xff09;2. 網格狀數據&#xff08;空間相關&#xff09;3. 圖結構數據&#xff08;非歐幾里得結構&#xff09;4. 其他特殊類型數據 &#xff08;重點&a…

C語言---常見的字符函數和字符串函數介紹

目錄 前言 1 字符分類函數 2 字符轉換函數 3 strlen的使用和模擬實現 3.1 strlen的模擬實現 4 strcpy的使用和模擬實現 4.1 strcpy的模擬實現 5 strcat的使用和模擬實現 5.1 strcat的模擬實現 6 strcmp的使用和模擬實現 6.1 strcmp的模擬實現 7 strncpy函數的使用…

Minio入門+適配器模式(實戰教程)

一、安裝Minio 1.1 拉取鏡像 docker pull minio/minio docker images 1.2創建掛載目錄 1.2.1 創建數據目錄 mkdir -p /docker-minio/data 1.2.2 創建配置文件目錄 mkdir -p /docker-minio/config 1.2.3 設置權限 chmod -R 777 /docker-minio/data /docker-minio/config …

LLaMA-Factory 對 omnisql 進行 ppo dpo grpo nl2sql任務 實現難度 時間 全面對比

在LLaMA-Factory框架下&#xff0c;針對omnisql任務&#xff08;自然語言到SQL生成&#xff09;應用PPO、DPO、GRPO三種算法的實現難度、時間及全面對比如下&#xff1a; 一、實現難度對比 1. PPO&#xff08;近端策略優化&#xff09; 難度&#xff1a;★★☆☆☆&#xff…

Kingbase 數據庫中的 sys_guid() 函數報錯

解決 Kingbase 數據庫中的 sys_guid() 函數報錯問題 問題背景 Kingbase 數據庫在遷移或使用過程中&#xff0c;可能會遇到 select sys_guid() 函數報錯 , 提示函數不存在的情況&#xff0c;這通常是由于以下幾種原因造成的&#xff1a; 函數未正確安裝或未啟用函數參數不符合…

零基礎RT-thread第五節:電容按鍵(2)

上一章的電容按鍵完全使用的HAL庫的代碼&#xff0c;并沒有使用線程。這里嘗試使用線程來控制電容按鍵。 依舊是 F767 本來以為會很容易實現&#xff0c;沒想到嘗試了很久&#xff0c;電容按鍵一直沒有反應。 static rt_uint32_t measure_charge_time(void) {// 步驟1: 放電 …

華為云Flexus+DeepSeek征文|單機部署 與 CCE 高可用部署下 Dify 性能實測

引言 在當今的 AI 應用開發領域&#xff0c;選擇合適的部署方式對于應用的性能表現、資源利用和成本控制至關重要。華為云為開發者提供了多樣化的部署選擇&#xff0c;其中基于單機 Flexus 實例的基礎版部署和基于 CCE 容器的高可用版部署是兩種常見的方式。本文將深入對比這兩…

釘釘小程序框架:Pinia 狀態管理與持久化存儲封裝

上一篇文章完成了 Pinia 在釘釘小程序中的引入與基礎配置 文章地址&#xff1a;釘釘小程序框架引入 Pinia 狀態管理-CSDN博客 本文將深入探討如何通過Pinia 結合持久化存儲 實現用戶狀態 在上一章節中&#xff0c;我們已經完成了 Pinia 在釘釘小程序中的引入與基礎配置。本章將…

云計算產業鏈

一、云計算定義與分類體系 本質特征 按需服務模式&#xff1a;以網絡化方式提供可配置的計算資源共享池&#xff08;網絡/服務器/存儲/應用&#xff09;。核心能力&#xff1a;快速彈性擴容、資源池化共享、按使用量付費、低管理開銷。技術原理&#xff1a;通過分布式計算將大型…