.NET9におけるポリシーベースの役割検証によるパッケージ衝突


今日、.NETプロジェクトでポリシーベースの役割認証を使用している際に、401の問題に遭遇しました。以下のようなシナリオです：

```csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

var authConfig = new AuthConfig();
builder.Configuration.Bind("AuthConfig", authConfig);
builder.Services.AddSingleton(authConfig);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, opt =>
    {
        opt.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(authConfig.SecurityKey)),
            ValidateIssuer = true,
            ValidIssuer = authConfig.Issuer,
            ValidateAudience = true,
            ValidAudience = authConfig.Audience,
            ClockSkew = TimeSpan.Zero,
            RequireExpirationTime = true,
            ValidAlgorithms = new[] { SecurityAlgorithms.HmacSha512 }
        };
    });
builder.Services.AddAuthorization(opt =>
{
    opt.AddPolicy("rolevalidate", policy => policy.RequireRole("user"));
});

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

app.MapPost("/login", ([FromServices] AuthConfig config, [FromBody] UserModel userModel) =>
{
    if (userModel.UserName != "gsw" || userModel.Password != "111111")
    {
        return new { result = false, message = "ユーザー名またはパスワードが間違っています！", token = "" };
    }
    else
    {
        var token = new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(
            issuer: config.Issuer,
            audience: config.Audience,
            claims: new[] {
                new Claim(ClaimTypes.Role, "user")
            },
            notBefore: DateTime.UtcNow,
            expires: DateTime.UtcNow.AddSeconds(config.Expires),
            signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.SecurityKey)), SecurityAlgorithms.HmacSha512)
        ));
        return new { result = true, message = "", token = token };
    }
}).AllowAnonymous();

app.MapGet("/index", () =>
{
    return "ログイン成功！";
}).RequireAuthorization("rolevalidate");

app.Run();

public class AuthConfig
{
    public string Issuer { get; set; }
    public string Audience { get; set; }
    public int Expires { get; set; }
    public string SecurityKey { get; set; }
}
public class UserModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
}
```

`appsettings.json`の内容は以下の通りです：

```json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Information"
    }
  },
  "AllowedHosts": "*",
  "AuthConfig": {
    "Issuer": "https://www.demo.com",
    "Audience": "https://www.demo.com",
    "Expires": 86400,
    "SecurityKey": "1234567890abcdefg1234567890abcdefg1234567890abcdefg1234567890abcdefg"
  }
}
```

導入したNuGetパッケージは以下の通りです（`Microsoft.IdentityModel.Tokens`パッケージは古い転送パッケージだと感じ、アップグレードしました）。

![パッケージ](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBHEMpatSibXaSwSqtysPVJNoPLlUZicwpzibgQJdk4mQYudicrMyIv8qtYRhYdm8SqWu8GGia1nwnMqJg/640?wx_fmt=png&from=appmsg)

テストを開始し、まずログインしてトークンが正常に返されました：

![ログイントークン](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBua1tbcFHN5SIGsJAzibicvUSxQw1l0KOQiboVfxrXksbnSAhLSOcw67sC2KrC1KPz5dljbmDUvSOiaA/640?wx_fmt=png&from=appmsg)

その後、/indexにアクセスすると、401エラーが発生しました。

![401エラー](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBua1tbcFHN5SIGsJAzibicvUsucJmqBqFkqibj0zS6pP04aJ3nWFR8elXlhUKIdg3Lnsfr7vcXo8Qqg/640?wx_fmt=png&from=appmsg)

最初はAddAuthenticationとAddAuthorizationの方法が間違っていると思い、再試行しましたが成功しませんでした。他の原因ではないかとログを確認し、失敗の理由を見つけて分析を進めることにしました。`Microsoft.AspNetCore.Authentication.JwtBearer`のログを有効にし、`appsettings.json`のLogLevelに以下を追加しました：

```json
    "Microsoft.AspNetCore.Authentication.JwtBearer": "Information"
```

再び/indexをリクエストすると、エラーログが表示されました：

![エラーログ](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBua1tbcFHN5SIGsJAzibicvULbShL82B3Nxs4CbBumgxMnF4cGqkPBaYEc7j29cUMKgdDyNcq4icYKw/640?wx_fmt=png&from=appmsg)

最終的に、`Microsoft.IdentityModel.Tokens`の問題が考えられたため、インストールしたバージョンを削除し、転送可能なバージョン8.0.1にダウングレードしました。

![バージョンダウングレード](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBua1tbcFHN5SIGsJAzibicvUt1kmb37QVRS8mZGsMB714bXgZgCZtaoRm6J01fKtXMFsIAtJntAdgA/640?wx_fmt=png&from=appmsg)

再度テストし、正常に通過しました！

![正常通過](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBua1tbcFHN5SIGsJAzibicvURDCZ4ibOxNuJ58CLNlMwOo5cSMKnoxgxKvDkglzIcx4vdFUUWFlSiayA/640?wx_fmt=png&from=appmsg)

(Translated by GPT)
元のリンク：https://mp.weixin.qq.com/s/vkYuFtcvqVMObLKwjGJQ6w?token=1700701408&lang=zh_CN&wt.mc_id=MVP_325642