簡體   English   中英

ASP.NET Core 6.0 中的 IAntiforgery 存在問題

[英]Having issues with IAntiforgery in ASP.NET Core 6.0

請在最后查看我的詳細回答,了解我是如何解決這個問題的。 我太沮喪了,又過了一天,有了新的視角和更多的睡眠,我找到了解決辦法。

我在 5.0 中執行此操作,在Startup.Configure方法中沒有問題。

基本上,我為受保護路由上的請求創建了一個 header。 我使用 React 作為前端。 當我將所有內容放入Program.cs時,我發現依賴注入、授權無法正常工作,因此我將其拆分為單獨的ProgramStartup文件。

但我不能像在 5.0 中那樣在 6.0 中使用以下簽名:

在 5.0 中工作的示例:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
{
    app.UseEndpoints(endpoints =>            
        {
            endpoints.MapGet("antiforgery/token", context =>
            {
                var tokens = antiforgery.GetAndStoreTokens(context);
                context.Response.Headers.Append("XYZ", tokens.RequestToken!);                    
                return Task.FromResult(StatusCodes.Status200OK);
            });                
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");
        });
}

Program.cs(我嘗試拆分程序和啟動 - 6.0)

var startup = new dolpassword.Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);

var app = builder.Build();

startup.Configure(app,app.Environment);

在微軟網站上看到了這個例子:

app.UseRouting();

app.UseAuthorization();
// app.Services syntax error in Configure for 6.0
var antiforgery = **app.Services.GetRequiredService<IAntiforgery>();**

 app.Use((context, next) =>
 {
      var requestPath = context.Request.Path.Value;

      if (string.Equals(requestPath, "/", 
            StringComparison.OrdinalIgnoreCase)
            || string.Equals(requestPath, "/index.html", 
              StringComparison.OrdinalIgnoreCase))
        {
            var tokenSet = antiforgery.GetAndStoreTokens(context);
             context.Response.Cookies.Append("XSRF-TOKEN", 
              tokenSet.RequestToken!,
        new CookieOptions { HttpOnly = false });
         }

         return next(context);
   });

我能夠在 6.0 中成功地做到這一點,所以我將分享一些代碼以及我是如何解決它的。 我還使用基於策略的授權進行了 Windows 身份驗證。 我將所有身份驗證/授權連接放在這篇文章中的原因是因為整個解決方案依賴於身份驗證、授權和防偽。

首先,我設置了我的服務。 我默認通過添加 ControllersWithViews 獲得 IAntiforgery,但我想使用我自己的 header 名稱,即 X-XSRF-TOKEN 而不是 .AspNet.Antiforgery.xxxx 或任何默認值。 我還需要 options.DefaultAuthenticateScheme = NegotiateDefaults.AuthenticationScheme; 讓 Windows 身份驗證工作。

string CorsPolicy = "CorsPolicy";
//===================================formerly Configure Services
WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);
ConfigurationManager _configuration = builder.Configuration;
// Add services to the container.
**IServiceCollection? services = builder.Services;
services.AddAntiforgery(options => { options.HeaderName = "X-XSRF-TOKEN"; 
options.Cookie.HttpOnly = false; });**
services.AddTransient<IActiveDirectoryUserService, ActiveDirectoryUserService>();
services.AddControllersWithViews();
services.AddAuthentication(options => {//needed for Windows authentication
    options.DefaultAuthenticateScheme = NegotiateDefaults.AuthenticationScheme;
});

添加更多...我正在使用 Windows 身份驗證,因此我正在使用協商提供程序。 然后我設置了我的授權。 我插入我自己的授權策略並添加我的聲明轉換器以使經過身份驗證的用戶進入聲明。 授權中的回退策略導致身份驗證異常。

services.AddAuthorization(options =>
{
    // options.FallbackPolicy = options.DefaultPolicy;//authorization bombs if you include this line
    options.AddPolicy("AuthenticatedOnly", policy => {
        policy.Requirements.Add(new AuthenticatedRequirement(true));
    });    
});
services.AddTransient<IClaimsTransformation, MyClaimsTransformer>();            
services.AddTransient<IAuthorizationHandler, AppUserRoleHandler>();
services.AddTransient<IAuthorizationHandler, AuthenticatedRoleHandler>();
services.AddCors(options =>
{
    options.AddPolicy(CorsPolicy,
    builder => builder
        .WithOrigins("https://localhost:7021","https://localhost:44414") 
         //Note:  The URL must be specified without a trailing slash (/).
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());
 });

現在我在中間件領域......如您所知,中間件中的順序很重要。 在 5.0 中,您可以將 IAntiforgery 添加到您的構造函數中,DI 將處理 rest。 在 program.cs 中你沒有那么奢侈。 幸運的是,您可以從服務集合中獲取它,您可以在以下代碼中看到它。

//==============formerly Startup.Configure=====================
WebApplication app = builder.Build();

app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseCookiePolicy();
app.UseCors(CorsPolicy);

IAntiforgery? antiforgery = app.Services.GetRequiredService<IAntiforgery>();

現在,當我設置端點路由時。 發現 UseRouting 和 Use.Endpoints 已成婚,需要配對。

我還創建了一個受保護的路由“/auth”(受我的授權策略保護)來獲取我們在服務集合中添加它時生成的防偽請求令牌。 所以這個 header 不會像 cookie 那樣在請求之間持久化。 最小的 API 允許我在不創建 controller 的情況下創建路線,並在單獨的 controller ZA2F2A198EBC2AB6BBB4C2 中執行操作。

app.UseEndpoints(endpoints =>          
{
    endpoints.MapGet("/auth", context =>
    {        
        var tokens = antiforgery.GetAndStoreTokens(context);
        context.Response.Headers.Append("XYZ", tokens.RequestToken!);       
        return Task.FromResult(Results.Ok());
    }).RequireAuthorization("AuthenticatedOnly");

    endpoints.MapControllerRoute(
        name: "default"
        pattern: "{controller}/{action=Index}/{id?}");
});

我的 React 前端將使用 fetch get 請求從 headers 集合中獲取令牌,然后堅持到第二個 post 請求,瞧,它可以工作了。

順便說一句,React 沒有像 Angular 那樣提供開箱即用的防偽功能,這與它的極簡主義 API 精神保持一致。

我要發布的操作如下所示:

[HttpPost]
[Authorize(Policy="AuthenticatedOnly")]
[ValidateAntiForgeryToken]
public string Update()

我完全意識到還有其他方法可以做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM