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

Posted

技术标签:

【中文标题】未指定 authenticationScheme,并且没有找到具有默认身份验证和自定义授权的 DefaultChallengeScheme【英文标题】:No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization 【发布时间】:2018-04-29 15:57:46 【问题描述】:

我有一个 .NET Core 2.0 应用程序,但存在授权问题。我想对特殊要求使用自定义授权。标头和标准默认身份验证。 首先,我在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(Task task)\r\n 在 Microsoft.AspNetCore .Mvc.ChallengeResult.d__14.MoveNext()\r\n--- 从先前引发异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\ n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__19.MoveNext()\r\n--- 从上一个位置结束堆栈跟踪在 System.Runtime.ExceptionServices.ExceptionDispatc 引发了异常 ---\r\n hInfo.Throw()\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\r\n 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext()\r\n---从先前引发异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\r \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(Task task)\r\n 在 React .AspNet.BabelFileMiddleware.d__5.MoveNext()\r\n--- 从先前引发异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\ n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\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 在 D:\Dev\microservicePDP\Template\core.common\ 中的 core.common.Middleware.LoggingMiddleware.d__3.MoveNext()中间件\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 中定义默认方案: 您希望用户自动登录 您使用 [Authorize] 属性或授权策略而不指定方案

我在ConfigureServices() 中添加了AuthenticationSchemeDefaultChallengeScheme。它没有帮助,这里同样的错误。我尝试在Startup.Configure() 方法中使用app.UseAuthentication();,但没有结果。

如何在没有身份验证的情况下使用自定义授权?

【问题讨论】:

所以在使用AddAuthentication之后,你又使用了[Authorize(Policy = Startup.DefaultAuthorizedPolicy)] ? 是的。不对吗? 我只是在确认您写的内容。我假设DefaultChallengeScheme 仅设置为默认授权策略....无论哪种方式尝试我的答案 【参考方案1】:

不要使用授权代替身份验证。我应该完全可以使用标头为所有客户提供服务。

工作代码是:

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:

public class PhoneNumberAuthenticationOptions : AuthenticationSchemeOptions

    public Regex PhoneMask  get; set; // = new Regex("7\\d10");

您应该定义静态类SchemesNamesConst。比如:

public static class SchemesNamesConst

    public const string TokenAuthenticationDefaultScheme = "TokenAuthenticationScheme";

【讨论】:

TokenAuthenticationOptions 类来自哪里?你是自己定义的还是来自图书馆? 你好。我现在找不到 TokenAuthenticationOptions,但它是空的。我找到了相同的类 PhoneNumberAuthenticationOptions 并将其添加到第一条评论 SchemesNamesConst 在哪里定义? 你好。我已经更新了第一条评论,它是在静态类中定义的。我这里没有相同但非常相似的项目github.com/galenam/MicroserviceTemplate 我不会投反对票,但请避免对您的答案做出不客观的结论,例如“这是最好的答案”或类似的东西。这不是一个论坛,在我的情况下它不会有帮助。提前致谢。【参考方案2】:

这对我有用

// using Microsoft.AspNetCore.Authentication.Cookies;
// using Microsoft.AspNetCore.Http;

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

【讨论】:

是的,这是最简单的解决方案【参考方案3】:

当我在设置默认身份验证方案之前使用策略时。我修改了DefaultPolicy,所以它略有不同。但是,添加策略也应如此。

services.AddAuthorization(options =>

    options.AddPolicy(DefaultAuthorizedPolicy, policy =>
    
        policy.Requirements.Add(new TokenAuthRequirement());
        policy.AuthenticationSchemes = new List<string>()
        
            CookieAuthenticationDefaults.AuthenticationScheme
        
    );
);

请注意默认情况下AuthenticationSchemes 属性使用只读列表。我认为实现它而不是 List 会更好。

【讨论】:

刚试过,异常很困难:“没有配置身份验证处理程序来对方案进行身份验证:Cookies”。我不想编写自定义 cookie 身份验证,也无法在谷歌上搜索对新异常有用的东西。 是的。你需要添加cookie AddAuthentication().AddCookie() 你好。我添加了 AddAuthentication().AddCookie() 和 policy.AuthenticationSchemes,之后我有 200 Ok 状态和正确的令牌和 404 有错误的令牌。我调试了代码并在 TokenAuthPolicy.HandleRequirementAsync 的方法中看到了 status=401,但客户端收到了 404。您知道网络核心在哪里将状态从 401 更改为 404 吗? 如果你使用令牌,你也可以试试.AddJTW()【参考方案4】:

您在标记解决方案中的初始陈述并不完全正确。虽然您的新解决方案可能会实现您最初的目标,但仍然可以在保留 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 各自的帖子),但授权处理程序仍然执行我们的授权策略。

【讨论】:

我从哪里得到这个? ValidTokenAuthenticationSchemeOptions, ValidTokenAuthenticationHandler, ValidTokenAuthorizationRequirement ?它不是 Microsoft.AspNetCore.Authorization 的一部分,我在 Google 上找不到它。【参考方案5】:

上面的许多答案都是正确的,但同时与 authN/authZ 的其他方面令人费解。 实际上解决了有问题的异常是这一行:

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

【讨论】:

以上是关于未指定 authenticationScheme,并且没有找到具有默认身份验证和自定义授权的 DefaultChallengeScheme的主要内容,如果未能解决你的问题,请参考以下文章

没有指定 authenticationScheme,也没有找到 DefaultChallengeScheme - ASP.NET core 2.1

asp.net核心未绑定当前用户

简单的web服务器

为啥我应该始终为我的 Authorize 属性定义 JwtBearerDefaults.AuthenticationScheme?

http 异步 接收 回传 数据文字和文件流

添加授权时缺少身份验证方案