我正在为ASP.NET Core API创建身份验证方案。
它会调用我的处理程序并击中断点,但是即使授权失败,API调用仍会返回结果。
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey(AuthorizationHeaderName))
{
//Authorization header not in request
return AuthenticateResult.Fail("Missing Authorization header");
}
据我幼稚的理解,如果认证失败,它不应返回数据。
我想念什么?
详细信息
我在Startup.ConfigureServices中注册这样的方案
services.AddAuthentication(options => {
// This (options.Default..Scheme) causes the default authentication scheme to be set.
// Without this, the Authorization header is not checked and
// you'll get no results.
options.DefaultAuthenticateScheme = BasicAuthenticationDefaults.AuthenticationScheme;
}).AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>("Basic", null);
Startup.Config调用
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
其余代码如下:
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
namespace WebAPI.Authentication
{
public interface IBasicAuthenticationService
{
Task<AuthenticateResult> HandleAuthenticateAsync();
}
public static class BasicAuthenticationDefaults
{
public const string AuthenticationScheme = "Basic";
}
public class BasicAuthenticationOptions : AuthenticationSchemeOptions
{ }
public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
private const string AuthorizationHeaderName = "Authorization";
private const string BasicSchemeName = "Basic";
public BasicAuthenticationHandler(
IOptionsMonitor<BasicAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey(AuthorizationHeaderName))
{ // Rejected here. Should fail.
//Authorization header not in request
return AuthenticateResult.Fail("Missing Authorization header");
}
if .... // never gets this far
}
return AuthenticateResult.Success(ticket);
}
}
}
这是不正确返回结果的控制器。
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace TMAWebAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
}
所有这些代码行都在调试器中被击中,因此该部分似乎正常工作。
但是,即使API调用通过身份验证失败,它仍然会返回结果。
更新:
向Controller添加AuthenticationScheme属性会使它失败。
像这样:
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = "Basic")]
public class ValuesController : ControllerBase
这不好。默认情况下,它应该失败,而不必将其添加到每个控制器中。
更新2:
为服务添加过滤器。AddMvc看起来很有前途,但这也不起作用。文档声称由于包含了它们,因此您不必实施授权过滤器。不是我能找到。
我继承了AuthorizeAttribute,使用了Matti Price和AddMvc所需的IFilterMetadata的思想。可以编译,但仍允许未经授权的访问。
public class BasicAuthorizeAttribute : AuthorizeAttribute, IFilterMetadata { }
services.AddMvc(options => {
options.Filters.Add(typeof(BasicAuthorizeAttribute));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
更新3:
尝试过
policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
如Matti所建议,但返回了
InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
我对重定向到API的不存在的登录页面没有兴趣,所以我尝试了
policy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes(new[] {BasicAuthenticationDefaults.AuthenticationScheme })
可以编译但抛出异常
InvalidOperationException Message=AuthorizationPolicy must have at least one requirement.
答案 0 :(得分:1)
您需要将[Authorize]
属性添加到控制器中,以使授权实际上对其结果执行任何操作。您可以像这样在全局添加它:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
答案 1 :(得分:0)
最终解决方案使用AddMVC。解决的办法是,除了添加一个方案外,该方案还需要一个条件。
这行得通。如果我不发送任何身份验证标头,它将返回一个空白页。如果我发送过期的标头,则发送500。应该是401。但是它不返回任何值,而这正是我所关心的。
public class TokenAuthorizationRequirement: IAuthorizationRequirement {}
services.AddMvc(config => {
var policy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(new[] {BasicAuthenticationDefaults.AuthenticationScheme })
.AddRequirements(new BasicAuthorizationRequirement())
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});