asp.net .Net 7 WebAPI使用401响应任何请求

ff29svar  于 2023-03-13  发布在  .NET
关注(0)|答案(1)|浏览(269)

长话短说:我已经创建了简单的webapi项目-.netCore 7.0-与cookie认证。每当我从外部客户端发出任何请求时,我只收到401早些时候,我有CORS的问题,但幸运的是,希望管理...
程序. cs代码:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using NawiaAPI;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Services.DbContext;
using System.Globalization;

var config = new ConfigurationBuilder().AddEnvironmentVariables().Build();
var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<AppSettings>(config.GetSection("AppSettings"));
builder.Services.AddDbContext<NawiaDbContext>(dbContextOptions =>
dbContextOptions.UseMySql(XXX,ServerVersion.AutoDetect(XXX))
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging()
.EnableDetailedErrors());
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromSeconds(10);
    options.Cookie.HttpOnly = false;
    options.Cookie.IsEssential = true;
});
builder.Services
    .AddCors()
    .AddResponseCompression()
    .AddControllers()
    .AddNewtonsoftJson(c =>
    {
        c.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
        c.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        c.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        c.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local;
        c.SerializerSettings.Culture = new CultureInfo("en-US");
        c.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
    options.SlidingExpiration = true;
    options.AccessDeniedPath = "/Forbidden/";
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;
        return Task.CompletedTask;
    };
});
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("UserPolicy", policy => policy.RequireClaim("User"));
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();
});
builder.Services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
    options.JsonSerializerOptions.DictionaryKeyPolicy = null;
});
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseRouting();
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");
    await next.Invoke();
});
app.UseCors(options => options
    .AllowAnyHeader()
    .AllowAnyMethod()
    .WithOrigins("https://localhost:4200")
    .AllowCredentials()
);
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.Run();

控制器实现:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Services;
using Services.DbContext;

namespace NawiaAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class AccountController : BaseController
    {
        private readonly AccountService _accountService;

        public AccountController(NawiaDbContext dbContext, IConfiguration configuration) : base(dbContext, configuration)
        {
            _accountService = new AccountService(dbContext);
        }

        [AllowAnonymous]
        [HttpPost("RegisterUser")]
        public IActionResult RegisterUser([FromBody] Models.Dtos.Requests.RegisterNewUserRequest entity)
        {
            return _accountService.RegisterNewUser(entity) ? Ok(true) : BadRequest(false);
        }
    }
}

错误样本:

> HttpErrorResponse {headers: HttpHeaders, status: 401, statusText:
> 'OK', url: 'https://localhost:7116/api/Account/RegisterUser', ok:
> false, …} error: null headers: HttpHeaders {normalizedNames: Map(0),
> lazyUpdate: null, lazyInit: ƒ} message: "Http failure response for
> https://localhost:7116/api/Account/RegisterUser: 401 OK" name:
> "HttpErrorResponse" ok: false status: 401 statusText: "OK" url:
> "https://localhost:7116/api/Account/RegisterUser"

示例客户端方法(Angular ):

public Register() {
    let t = this;
    t.http.post<boolean>(t.State.webApiUrl + t.State.webApiCommandAccountRegisterUser, t.register_req).subscribe(res => {
      console.log(res);
    }
    )
  };
lb3vh1jj

lb3vh1jj1#

在我的本地测试后,我发现这是由OnRedirectToLogin和AllowAnonymous之间的冲突引起的。

测试我这边的代码:

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
        {
            options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
            options.SlidingExpiration = true;
            options.AccessDeniedPath = "/Forbidden/";
            options.Events.OnRedirectToLogin = context =>
            {
                //context.Response.StatusCode = 401;
                //return Task.CompletedTask;
                if (context.Request.Path.StartsWithSegments("/Account/RegisterUser"))
                {
                    // Allow unauthorized users to pass through and access /Account/RegisterUser
                    return Task.CompletedTask;
                }
                else
                {
                    // All other unauthorized users return 401
                    context.Response.StatusCode = 401;
                    return Task.CompletedTask;
                }
                
            };
           
        });

概念

当客户端需要重定向到登录URL时调用。
Simple authorization in ASP.NET Core - AllowAnonymous
简单地说,如果未经授权的用户发送http请求,它将在OnRedirectToLogin方法中处理。它不会命中控制器中的方法,并获得401代码作为您以前的代码。在我的示例中,它允许您访问端点/Account/RegisterUser,并且不执行任何操作,然后它将命中控制器中的方法。

相关问题