未指定authenticationScheme,并且未找到DefaultChallengeScheme,默认身份验证和自定义授权

时间:2017-11-16 07:43:11

标签: c# asp.net .net asp.net-core-2.0

我有一个net core 2.0应用程序和授权问题。我想使用具有特殊request.header和标准默认身份验证的自定义授权。 首先,我在startup.cs中添加配置:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
  ...
services.AddAuthorization(options =>
            {
                options.AddPolicy(DefaultAuthorizedPolicy, policy =>
                {
                    policy.Requirements.Add(new TokenAuthRequirement());
                });
            });
services.AddSingleton<IAuthorizationHandler, AuthTokenPolicy>();
  ...
}

和AuthTokenPolicy.cs

public class AuthTokenPolicy : AuthorizationHandler<TokenAuthRequirement>
{   
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TokenAuthRequirement requirement)
    {
        var filterContext = context.Resource as AuthorizationFilterContext;
        var response = filterContext.HttpContext.Response;
        try
        {
            // some validation code

            var isValidToken = isValidTokenTask.Result;
            if (!isValidToken)
            {
                response.StatusCode = 401;
                return Task.CompletedTask;
            }

            response.StatusCode = 200;
            context.Succeed(requirement);
        }
        catch (Exception)
        {
            return Task.CompletedTask;
        }
        return Task.CompletedTask;
    }
}

和HomeController.cs

[Authorize(Policy = Startup.DefaultAuthorizedPolicy)]
    public async Task<IActionResult> IsVisible()

如果我在AuthTokenPolicy中使用错误的request.header,我会看到它。但在日志中我看到错误:

  

System.InvalidOperationException:未指定authenticationScheme,并且未找到DefaultChallengeScheme。\ r \ n在Microsoft.AspNetCore.Authentication.AuthenticationService.d__11.MoveNext()\ r \ n ---以前的堆栈跟踪结束抛出异常的位置--- \ r \ n在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\ r \ n,在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在Microsoft.AspNetCore上.Mvc.ChallengeResult.d__14.MoveNext()\ r \ n ---从抛出异常的上一个位置开始的堆栈跟踪结束--- \ r \ n在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\ r \在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__19.MoveNext()\ r \ n ---从上一个位置的堆栈跟踪结束在System.Runtime.ExceptionServices.ExceptionDispatc中抛出异常--- \ r \ n hInfo.Throw()\ r \ n在Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext()\ r抛出异常的前一个位置的堆栈跟踪结束---在System.Runtime.ExilerServices.ExceptionDispatchInfo.Throw()\ r \ n中的系统.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n \ n在Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext()\ r \ n ---从抛出异常的上一个位置的堆栈跟踪结束--- \ r \ n在System.Runtime.ExceptionServices。 ExceptionDispatchInfo.Throw()\ r \ n在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()\ r \ n ---结束从抛出异常的先前位置堆栈跟踪--- \ r \ n在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Thr ow()\ r \ n在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.d__3.MoveNext()\ r \ n ---堆栈跟踪结束从抛出异常的先前位置--- \ r \ n在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\ r \ n在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在React .AspNet.BabelFileMiddleware.d__5.MoveNext()\ r \ n ---从抛出异常的上一个位置开始的堆栈跟踪结束--- \ r \ n在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\ r \ n在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext()\ r \ n ---从前一个位置的堆栈跟踪结束,其中异常是抛出--- \ r \ n在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() \ r \ n在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\ r \ n在core.common.Middleware.LoggingMiddleware.d__3.MoveNext()在D:\ Dev \ microservicePDP \ Template \ core.common \ Middleware \ LoggingMiddleware.cs:第72行

阅读Migrating Authentication and Identity to ASP.NET Core 2.0后,我已在startup.cs中添加了此代码

文章的引文:

services.AddAuthentication(options => 
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
  

如果满足下列条件之一,则在2.0中定义默认方案:   您希望用户自动登录   您可以使用[授权]属性或授权策略,而无需指定方案

我在ConfigureServices中添加了AuthenticationScheme和DefaultChallengeScheme。它没有帮助,这里也是同样的错误。我尝试过使用app.UseAuthentication();在StartUp.cs中的Configure中,没有结果。 有人可以解释如何在没有身份验证的情况下使用自定义授权吗?

6 个答案:

答案 0 :(得分:12)

奥基。正确答案是:不要使用授权而不是身份验证。我应该获得使用标头服务所有客户端的完全访问权限。 工作代码是:

public class TokenAuthenticationHandler : AuthenticationHandler<TokenAuthenticationOptions> 
{
    public IServiceProvider ServiceProvider { get; set; }

    public TokenAuthenticationHandler (IOptionsMonitor<TokenAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IServiceProvider serviceProvider) 
        : base (options, logger, encoder, clock) 
    {
        ServiceProvider = serviceProvider;
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync () 
    {
        var headers = Request.Headers;
        var token = "X-Auth-Token".GetHeaderOrCookieValue (Request);

        if (string.IsNullOrEmpty (token)) {
            return Task.FromResult (AuthenticateResult.Fail ("Token is null"));
        }           

        bool isValidToken = false; // check token here

        if (!isValidToken) {
            return Task.FromResult (AuthenticateResult.Fail ($"Balancer not authorize token : for token={token}"));
        }

        var claims = new [] { new Claim ("token", token) };
        var identity = new ClaimsIdentity (claims, nameof (TokenAuthenticationHandler));
        var ticket = new AuthenticationTicket (new ClaimsPrincipal (identity), this.Scheme.Name);
        return Task.FromResult (AuthenticateResult.Success (ticket));
    }
}

Startup.cs:

#region Authentication
services.AddAuthentication (o => {
    o.DefaultScheme = SchemesNamesConst.TokenAuthenticationDefaultScheme;
})
.AddScheme<TokenAuthenticationOptions, TokenAuthenticationHandler> (SchemesNamesConst.TokenAuthenticationDefaultScheme, o => { });
#endregion

和mycontroller.cs

[Authorize(AuthenticationSchemes = SchemesNamesConst.TokenAuthenticationDefaultScheme)]
public class MainController : BaseController
{ ...}

我现在找不到TokenAuthenticationOptions,但它是空的。我找到了同一个类PhoneNumberAuthenticationOptions:

namespace Project.Auth{
public class PhoneNumberAuthenticationOptions : AuthenticationSchemeOptions
{
    public Regex PhoneMask { get; set; }// = new Regex("7\\d{10}");

}}

您应该定义静态类SchemesNamesConst 类似的东西:

namespace Common.Const{
public static class SchemesNamesConst
{
    public const string SchemesNamesConst= "TokenAuthenticationScheme";
}}

答案 1 :(得分:4)

在我使用策略之前,我也将默认身份验证方案设置到其中。我修改了css所以它略有不同。但是,同样适用于添加策略也是如此。

DefaultPolicy

请注意,默认services.AddAuthorization(options => { options.AddPolicy(DefaultAuthorizedPolicy, policy => { policy.Requirements.Add(new TokenAuthRequirement()); policy.AuthenticationSchemes = new List<string>() { CookieAuthenticationDefaults.AuthenticationScheme } }); }); 属性使用只读列表。我认为最好实现它而不是List。

答案 2 :(得分:3)

这对我有用

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
        options =>
        {
            options.LoginPath = new PathString("/auth/login");
            options.AccessDeniedPath = new PathString("/auth/denied");
        });

答案 3 :(得分:0)

您在带标记的解决方案中的初始陈述并不完全正确。尽管您的新解决方案可以实现您的原始目标,但是仍然可以避开原始错误,同时保留AuthorizationHandler逻辑-提供,即使基本的身份验证方案处理程序在功能上是骨架,也可以使用它们。

广义上讲,身份验证处理程序和方案旨在建立+验证身份,这使它们成为授权处理程序/策略正常运行所必需的-因为它们以已建立身份为前提。

ASP.NET Dev Haok在这里总结了最好的最佳做法:“当今的身份验证根本不了解授权,它只关心在每个方案中生成ClaimsPrincipal。授权必须在某种程度上了解身份验证,因此策略中的AuthenticationSchemes是一种机制,可将策略与用于构建有效的声明主体以进行授权的方案相关联(或者它仅使用默认的httpContext.User进行请求,而该请求确实依赖DefaultAuthenticateScheme)。” https://github.com/aspnet/Security/issues/1469

在我的案例中,我正在研究的解决方案提供了自己的隐式身份概念,因此我们不需要身份验证方案/处理程序-仅用于授权的标头令牌。因此,在我们的身份概念改变之前,可以将执行策略的标头令牌授权处理程序绑定到一对一方案框架。

端点上的标记:

[Authorize(AuthenticationSchemes = "AuthenticatedUserSchemeName", Policy = "AuthorizedUserPolicyName")]

Startup.cs:

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = "AuthenticatedUserSchemeName";
        }).AddScheme<ValidTokenAuthenticationSchemeOptions, ValidTokenAuthenticationHandler>("AuthenticatedUserSchemeName", _ => { });

        services.AddAuthorization(options =>
        {
            options.AddPolicy("AuthorizedUserPolicyName", policy =>
            {
                //policy.RequireClaim(ClaimTypes.Sid,"authToken");
                policy.AddAuthenticationSchemes("AuthenticatedUserSchemeName");
                policy.AddRequirements(new ValidTokenAuthorizationRequirement());
            });
            services.AddSingleton<IAuthorizationHandler, ValidTokenAuthorizationHandler>();

空的身份验证处理程序授权处理程序都被调用(在设置上类似于OP的相应帖子),但是授权处理程序仍会执行我们的授权策略。

答案 4 :(得分:0)

如果您是在Visual Studio中使用Asp.Net核心项目执行此操作的,而您的应用程序突然不是以下面所述的错误消息开头,那么对我有用的是取消选中“启用浏览器”链接”

uncheck this option

错误:

Conversion> [13:31:10 ERR] Connection id "0HLJ153E20LDJ", Request id "0HLJ153E20LDJ:00000003": An unhandled exception was thrown by the application.
Conversion> System.ObjectDisposedException: The response has been aborted due to an unhandled application exception. ---> System.FormatException: Invalid ETag name
Conversion>    at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag, Boolean isWeak)
Conversion>    at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleWareUtil.AddToETag(ResponseHeaders responseHeader, Int32 port)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware.<>c__DisplayClass7_0.<ExecuteWithFilter>b__0()
Conversion>    at Microsoft.AspNetCore.Http.HttpResponse.<>c.<.cctor>b__30_0(Object callback)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FireOnStartingMayAwait(Stack`1 onStarting)
Conversion>    --- End of inner exception stack trace ---
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAbortedException()
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory`1 data, CancellationToken cancellationToken)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
Conversion>    at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.ScriptInjectionFilterStream.<>c__DisplayClass37_0.<<CreateResponseHandler>b__0>d.MoveNext()
Conversion> --- End of stack trace from previous location where exception was thrown ---
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.SocketReader.ReadBytesIntoResponseHandler(Int64 totalBytesToRead, ResponseHandler handler, CancellationToken cancellationToken)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadBytesIntoResponse(Int64 bytesToRead)
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadChunkedContent()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadResponse()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.DelayConnectingHttpSocketAdapter.Microsoft.VisualStudio.Web.BrowserLink.IHttpSocketAdapter.WaitForResponseComplete()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.ScriptInjectionFilterStream.WaitForFilterComplete()
Conversion>    at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware.ExecuteWithFilter(IHttpSocketAdapter injectScriptSocket, String requestId, HttpContext httpContext)
Conversion>    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Conversion>    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Conversion>    at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)
Conversion>    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

答案 5 :(得分:0)

上面的许多答案是正确的,但同时又与authN / authZ的其他方面混淆了。实际上, 解决以下异常的情况是:

services.AddScheme<YourAuthenticationOptions, YourAuthenticationHandler>(YourAuthenticationSchemeName, options =>
    {
        options.YourProperty = yourValue;
    })