gpt4 book ai didi

c# - 从 .NET Core 2.2 迁移到 3.1 后,ASP.NET Core 自定义 AuthenticationHandler 中不会忽略 AllowAnonymous

转载 作者:行者123 更新时间:2023-12-02 04:08:50 27 4
gpt4 key购买 nike

我有一个 ASP.NET Core 2.2 Web API,它可以使用基本身份验证。到目前为止,它运行良好,没有出现任何问题。在其中一个 Controller 中,一个操作方法用 [AllowAnonymous] 装饰,以像往常一样进行用户登录。

[Produces("application/json")]
[Route("user")]
[AllowAnonymous]
[ApiController]
public class LoginController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly IMessagingService _messageService;
private readonly IBasicAuthenticationService _basicAuthenticationService;
private readonly string PWAPIBaseUrl;

public LoginController(IConfiguration configuration, ILogger<LoginController> logger, IMessagingService messagingService, IBasicAuthenticationService authenticationService)
{
_configuration = configuration;
_logger = logger;
_messageService = messagingService;
_basicAuthenticationService = authenticationService;
}

[HttpGet]
[AllowAnonymous]
[Route("login/{username}/{clientID}")]
public async Task<IActionResult> UserLogin(string username, string clientID)
{
// Check the Credentials Manually
string failReason = "";
if (!CheckCredentials(out failReason))
{
return StatusCode(StatusCodes.Status403Forbidden, userInfo);
}

// Load the Roles and UI Preferences ...

}
}

由于 .NET Core 2.2 即将结束,我尝试升级到 .NET Core 3.1 并遵循 official Migration Guide并成为必要的changes 。尽管应用程序启动顺利,但存在一个错误问题,导致无法升级。

在上述 Controller 上,[AllowAnonymous] 不会被忽略,并且会评估身份验证并抛出错误。但Login方法是在之后执行的。这会导致登录在所有相关应用程序中中断。我已经尝试了 Stackoverflow 的所有建议,例如 this , thisthis .

基本身份验证处理程序:

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly ILogger<BasicAuthenticationHandler> _logger = null;
private readonly IBasicAuthenticationService _basicAuthenticationService;

public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
UrlEncoder encoder,
ILoggerFactory loggerFactory,
ISystemClock clock,
IBasicAuthenticationService authenticationService)
: base(options, loggerFactory, encoder, clock)
{
_logger = loggerFactory.CreateLogger<BasicAuthenticationHandler>();
_basicAuthenticationService = authenticationService;
}

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var config = Util.GetConfig();

if (!Request.Headers.ContainsKey("Authorization"))
{
_logger.LogError("No authorization credentials");
return AuthenticateResult.NoResult();
}

if (!Request.Headers.ContainsKey("ClientID"))
{
_logger.LogError("Missing header client token");
return AuthenticateResult.Fail("Missing header client token");
}

var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
if (authHeader.Scheme != "Basic")
{
_logger.LogError("Authentication scheme not recognized");
return AuthenticateResult.Fail("Authentication scheme not recognized");
}

var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':');
var username = credentials[0];
var password = credentials[1];

string fullname = "";
string failReason = "";
bool t = false;

IPrincipal principal = null;

// Do Business Validation against the DB

if (!t) // login failed
{
byte[] bEncodedResponse = Encoding.UTF8.GetBytes(failReason);
await Context.Response.Body.WriteAsync(bEncodedResponse, 0, bEncodedResponse.Length);
return AuthenticateResult.Fail(failReason);
}
else
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, username),
new Claim(ClaimTypes.Name, fullname),
};

var identity = new ClaimsIdentity(claims, Scheme.Name);
principal = principal==null?new ClaimsPrincipal(identity): principal;
var ticket = new AuthenticationTicket(principal as ClaimsPrincipal, Scheme.Name);

return AuthenticateResult.Success(ticket);
}
}


}

启动.cs

public class Startup
{
public Startup(IWebHostEnvironment environment, IConfiguration configuration, ILoggerFactory loggerFactory)
{
Environment = environment;
Configuration = configuration;
LoggerFactory = loggerFactory;
}

public IConfiguration Configuration { get; }
public ILoggerFactory LoggerFactory { get; }
public IWebHostEnvironment Environment { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

// Adding the Configuration Options -- Extension Methods to Inject Configuration as IOption POCOs
services.ConfigureAPIOptions(Configuration);

// configure DI for application services -- Other DI Objects
services.ConfigureDependencies(Configuration, LoggerFactory);

Common.APIConfiguration.Current = Configuration;

services.AddControllers();
services.AddAuthorization();
if (Environment.IsDevelopment())
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "My Materials API", Version = "v1" });
});
}
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();

if (env.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Materials API v1");
c.RoutePrefix = string.Empty;
});
}

app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

我仍然对我做错了什么一无所知,并且我可能在 ASP.NET Core 3.1 中遗漏了一些东西。请帮助我完成这项工作。提前致谢。

编辑1:

服务扩展.cs

public static class ServiceExtensions
{
public static void ConfigureAPIOptions(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions();
services.Configure<DataSetting>(configuration.GetSection("DataSettings"));
services.Configure<UrlSetting>(configuration.GetSection("UrlSettings"));
services.Configure<SiteSettings>(configuration.GetSection("SiteSettings"));
}

public static void ConfigureDependencies(this IServiceCollection services, IConfiguration configuration, ILoggerFactory loggerFactory)
{
services.AddSingleton<IConfiguration>(configuration);
services.AddScoped<IBasicAuthenticationService, BasicAuthenticationService>();
services.AddScoped<IMessagingService>(s => new MessagingServices(configuration, loggerFactory.CreateLogger<MessagingServices>()));
services.AddHostedService<TimedHostedService>();
}
}

用于访问配置的小组合,其中 DI 是不可能的。

public static class APIConfiguration
{
public static IConfiguration Current { get; set; }
}

最佳答案

我尝试过这个,它确实对我有帮助。

private static bool HasAllowAnonymous(AuthorizationFilterContext context)
{
var filters = context.Filters;
for (var i = 0; i < filters.Count; i++)
{
if (filters[i] is IAllowAnonymousFilter)
{
return true;
}
}

// When doing endpoint routing, MVC does not add AllowAnonymousFilters for AllowAnonymousAttributes that
// were discovered on controllers and actions. To maintain compat with 2.x,
// we'll check for the presence of IAllowAnonymous in endpoint metadata.
var endpoint = context.HttpContext.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
return true;
}

return false;
}

https://github.com/dotnet/aspnetcore/blob/bd65275148abc9b07a3b59797a88d485341152bf/src/Mvc/Mvc.Core/src/Authorization/AuthorizeFilter.cs#L236

这里提到了https://learn.microsoft.com/en-us/dotnet/core/compatibility/2.2-3.1#authorization-iallowanonymous-removed-from-authorizationfiltercontextfilters

关于c# - 从 .NET Core 2.2 迁移到 3.1 后,ASP.NET Core 自定义 AuthenticationHandler 中不会忽略 AllowAnonymous,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59310193/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com