究竟是什么' UseAuthentication()'对于?

时间:2018-02-17 00:21:02

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

我对ASP.NET Core 2中的身份验证有疑问:对于 app.UseAuthentication()的调用究竟是什么?

这是一个基本的先决条件,以便我可以实现我的自定义身份验证逻辑吗?我已经看过UseAuthentication以及实际中间件AuthenticationMiddleware的实现,但说实话,我不明白实际做了什么以及为什么有必要。

换句话说:

我是否需要拨打 UseAuthentication() enter image description here

或者它是一个很好的,我可以做我的自定义身份验证吗? enter image description here

如果我没有打电话给 UseAuthentication(),我仍然对AuthenticationMiddleware实际上在做什么感兴趣。所以,如果你知道如果你能为我解释,我会非常感激。

4 个答案:

答案 0 :(得分:10)

如果您编写自定义中间件(就像您在示例中所做的那样),则无需调用AddAuthentication,因为身份验证中间件不会识别您自己的中间件。

话虽这么说,您可能不想创建自己的中间件:您可能希望创建一个与ASP.NET身份验证框架很好地配合的新身份验证处理程序(以便您使用[Authorize]属性在控制器上。)

要创建自定义身份验证,您必须创建一个继承自AuthenticationHandler的专用处理程序,并实现相关方法。您可以在github上查看基本身份验证的示例:https://github.com/blowdart/idunno.Authentication,但这是一个快速示例,用于显示自定义处理程序的要点。

public class BasicAuthenticationOptions : AuthenticationSchemeOptions
{
    public BasicAuthenticationOptions()
    {
    }
}

internal class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
    private const string _Scheme = "MyScheme";

    public BasicAuthenticationHandler(
        IOptionsMonitor<BasicAuthenticationOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock) : base(options, logger, encoder, clock)
    {
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        string authorizationHeader = Request.Headers["Custom-Auth-Handler"];

        // create a ClaimsPrincipal from your header
        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, "My Name")
        };

        var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));
        var ticket = new AuthenticationTicket(claimsPrincipal,
            new AuthenticationProperties { IsPersistent = false },
            Scheme.Name
        );

        return AuthenticateResult.Success(ticket);
    }

然后,您可以在Startup.cs

中注册新方案
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme)
        .AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>("MyScheme", options => { /* configure options */ })
}

答案 1 :(得分:0)

你需要打电话。

UseAuthentication()记录为:

  

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.authappbuilderextensions.useauthentication?view=aspnetcore-2.0

     

将AuthenticationMiddleware添加到指定的IApplicationBuilder,后者启用身份验证功能。

它基本上是这样做的:

IApplicationBuilder AddAuthentication(this IApplicationBuilder app) {

    return app.UseMiddleware<AuthenticationMiddleware>();
}

...所以它只是为你节省了一些打字,可能还有一些额外的using进口。

这会在流程中添加AuthenticationMiddleware个实例。请求处理管道,此特定对象添加管道以进行身份​​验证。

答案 2 :(得分:0)

尽管这是一个老话题,但是由于我最近偶然发现了一个相同的问题,我认为在内部进行更多的了解可能会使其他人受益

简短的答案取决于您的服务类型和API。您不需要在以下情况下需要致电UseAuthentication

  1. 您将实现自己的用于身份验证的中间件-无需在此处进行详细说明。您可以自己处理所有事情,并且显然不需要其他依赖项
  2. 您不需要自动远程身份验证

远程身份验证

需要重定向到身份提供者的身份验证,例如OpenID Connect。

有什么特别之处?

这些中间件需要关联不同的http调用。

最初的调用首先由中间件处理,然后重定向到身份提供者(用户需要登录),然后再返回到中间件。 在这种情况下,中间件需要拥有请求,并且不允许其他身份验证中间件参与该过程。

这是middleware代码的第一部分:

// Give any IAuthenticationRequestHandler schemes a chance to handle the request
var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
{
    var handler = await handlers.GetHandlerAsync(context, scheme.Name) as 
    IAuthenticationRequestHandler;
    if (handler != null && await handler.HandleRequestAsync()) 
    {
        return;
    }
}
  • 这当然是一个简化的解释,因为远程处理程序更加复杂。目标最终是集中精力并解释中间件的行为

自动身份验证

针对默认方案自动运行的身份验证。顾名思义,如果您定义了默认的身份验证方案,则与中间件关联的身份验证处理程序将始终运行。

直观上,您希望认证中间件首先运行,特别是它们应该在MVC层(即控制器)之前运行。但是,这也意味着认证层不知道哪个控制器应该运行,也不知道那些控制器的授权要求,换句话说,它不知道应该评估什么授权策略[Authorize("Policy")]

从逻辑上讲,我们希望首先评估策略,然后再运行身份验证逻辑。这就是为什么身份验证处理程序在ASP 2. *中迁移为常规服务而不与中间件耦合的原因。

但是,在某些情况下,无论您使用何种策略,都始终希望身份验证处理程序运行。在这种情况下,您可以定义将自动运行的默认身份验证方案。

这说明了middleware代码的第二部分:

var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
    if (defaultAuthenticate != null)
    {
        var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
        if (result?.Principal != null)
        {
            context.User = result.Principal;
        }
}

如果您正在开发支持多种身份验证方案的REST API,或者混合使用经过身份验证的控制器和未经身份验证的控制器,则不需要自动身份验证,因为它会增加冗余。

结论

这给我们带来了一个有趣的问题和答案:当认证不是自动且非远程时,何时何地进行认证?

在正常的MVC授权流程中,这发生在调用IAuthenticationService.AuthenticateAsync的AuthorizeFilter类中。

  • 如果您实现自己的授权层或使用较低级别的API(例如未实现为控制器的websocket),则可以自己调用此方法

在这些情况下,不需要致电UseAuthentication

答案 3 :(得分:0)

来自 UseAuthentication 的 GitHub 源代码。

    public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }
        
        return app.UseMiddleware<AuthenticationMiddleware>();
    }

如您所见,它只是添加了一个名为 AuthenticationMiddleware 的中间件。

而这正是 AuthenticationMiddleware 正在做的:

 public async Task Invoke(HttpContext context)
        {
            context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
            {
                OriginalPath = context.Request.Path,
                OriginalPathBase = context.Request.PathBase
            });

            // Give any IAuthenticationRequestHandler schemes a chance to handle the request
            var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
            foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
            {
                var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
                if (handler != null && await handler.HandleRequestAsync())
                {
                    return;
                }
            }

            var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
            if (defaultAuthenticate != null)
            {
                var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
                if (result?.Principal != null)
                {
                    context.User = result.Principal;
                }
                if (result?.Succeeded ?? false)
                {
                    var authFeatures = new AuthenticationFeatures(result);
                    context.Features.Set<IHttpAuthenticationFeature>(authFeatures);
                    context.Features.Set<IAuthenticateResultFeature>(authFeatures);
                }
            }

            await _next(context);
        }
相关问题