沒事把node.js簽發的jwt拿來呼叫.net core web API時踩了一堆坑的故事
照理說dot net 的 web api與nextjs整合應該是前端用Browser -->next.js --> .net web api (讓dot net的microservice放在另一個網段)
不過如果直接讓node.js簽發給browser client的jwt拿來call .net web api會發生什麼事 (為什麼要這樣做?不為什麼,就只是想知道罷了)
這一路走來我遇到了狀況,因為很有趣,所以把它做個記錄.
狀況一.401錯誤--起源是錯用了AOT,而不是傳統的Web API專案
原因: VS 2026 建專案時選到了 "Web API (Native AOT)" 模板,使用 CreateSlimBuilder + PublishAot。AOT 的 trimmer 會把 JWT 需要的 crypto provider 砍掉。
AOT與一般web API專案的差別:
重新增加一個web api project,修改program.cs
-----------------------------
之後.......builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = key, ValidateIssuer = false, ValidateAudience = false, }; });
...
var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(Configuration["JWT_SECRET"]) );
....
...app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
-----------------------------
Action in Sample controller
-------------------------[Authorize] [HttpGet] public IActionResult Get() { var username = User.FindFirst("username")?.Value; var role = User.FindFirst("role")?.Value; return Ok(); }----------------------------
狀況二.錯誤訊息 IDX10517: Signature validation failed. The token's kid is missing.
------------------------------------------
原因: .NET 10 的
Microsoft.IdentityModel 套件收緊了驗證規則,要求 token header 中必須有 kid(Key ID)。而 Node.js 的 jose 預設不產生 kid。解法:
這要在nextjs 簽發JWT及解析端(.net core web API)都要再加一個kid
------JWT.ts-----------
var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(Configuration["JWT_SECRET"]) );--------------------------key.KeyId = "MyKidKey"; <----KID set here.
這下子,總該可以了吧?
再次用postman設定好bearer token後,試著request controller 時
出現新的錯誤錯誤--
狀況三:「The signature is invalid」錯誤
這東西真的是超難解的,最後是把兩邊的code都送給AI去看的結果才知是「長度」問題:
原因: HS256 要求 key 至少 256 bits(32 bytes)。原本的 secret 只有 27 字元,jose 和 .NET 對不足長度的 key 可能有不同的 padding 行為。
解法: Secret 改成 32 字元以上,兩邊同步更新。
最後,終於在controller的GET action中,可以讀取到User資訊了
但是「User.FindFirst("role")?.Value」回傳null,這樣還是不完成,
改成「User.FindFirst(ClaimTypes.Role)?.Value」,就會得到role值了
別忘了,在[Authorize...]指定需要的角色權限.ex [Authorize(Roles = "manager,admin")]
有些知識真的是靠踩坑得來的,不是AI直接給你就會了解的.


0 個意見:
張貼留言
訂閱 張貼留言 [Atom]
<< 首頁