没有ASP.NET身份的.NET Core外部身份验证

Ref*_*eft 9 .net c# oauth-2.0 asp.net-identity asp.net-core

我使用自己的JWT令牌身份验证,而不使用默认模板附带的asp.net身份。我到处都到处寻找有关如何在没有asp.net身份的情况下实现外部身份验证的文档/指南,但是所有文章都涉及asp.net身份验证。

我已经设法将用户重定向到google登录页面(使用ChallengeResult),但是当提供程序重定向回该应用程序时,我失败了。

我删除了:app.UseAuthentication(); Startup.cs中,(禁用身份验证),然后可以使用回调函数,但是我不知道如何在不使用登录管理器的情况下从响应中检索数据。

启动

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();

        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["Authentication:Secret"]));

        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = signingKey,
            ValidateIssuer = true,
            ValidIssuer = Configuration["Urls:Base"],
            ValidateAudience = true,
            ValidAudience = Configuration["Urls:Base"],
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero
        };

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o =>
        {
            o.TokenValidationParameters = tokenValidationParameters;
        }
        ).AddGoogle(googleOptions =>
        {
            googleOptions.ClientId = "x";//Configuration["Authentication:Google:ClientId"];
            googleOptions.ClientSecret = "x";//Configuration["Authentication:Google:ClientSecret"];
            googleOptions.CallbackPath = "/api/authentication/externalauthentication/externallogincallback";
        });

        services.Configure<RequestLocalizationOptions>(
            opts =>
            {
                var supportedCultures = new List<CultureInfo>
                {
                        new CultureInfo("en"),
                        new CultureInfo("sv")
                };

                opts.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");
                opts.SupportedCultures = supportedCultures;
                opts.SupportedUICultures = supportedCultures;
            });

        services.AddMvc(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();

            config.Filters.Add(new AuthorizeFilter(policy));
        });

        services.RegisterAppSettings(Configuration);

        services.AddOptions();

        services.InjectServices();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseAuthentication();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();

            EndpointsAppSettings endpointAppSettings = new EndpointsAppSettings();
            Configuration.GetSection("Endpoints").Bind(endpointAppSettings);

            app.UseCors(builder =>
            {
                builder.WithOrigins(endpointAppSettings.Aurelia)
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
            });
        }

        var logService = app.ApplicationServices.GetService<ILogService>();

        loggerFactory.AddProvider(new LogProvider(logService));

        app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value);

        app.UseMvc();

        app.UseDefaultFiles();

        app.UseStaticFiles();
    }
}
Run Code Online (Sandbox Code Playgroud)

控制者

[Route("api/authentication/[controller]")]
public class ExternalAuthenticationController : Controller
{
    [AllowAnonymous]
    [HttpPost(nameof(ExternalLogin))]
    public IActionResult ExternalLogin(ExternalLoginModel model)
    {
        if (model == null || !ModelState.IsValid)
        {
            return null;
        }

        var properties = new AuthenticationProperties { RedirectUri = "http://localhost:3000/#/administration/organisations" };

        return Challenge(properties, model.Provider);
    }

    [AllowAnonymous]
    [HttpGet(nameof(ExternalLoginCallback))]
    public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
    {
        if (remoteError != null)
        {
            return null;
        }

        //Help me retrieve information here!

        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

ExternalLoginCallback的堆栈跟踪

信息:Microsoft.AspNetCore.Hosting.Internal.WebHost [1]请求启动HTTP / 1.1 GET http:// localhost:5000 / api / authentication / externalauthentication / externallogincallback?state = CfDJ8CyKJfDTf--HIDDEN DATA--52462e4156a..5cde&prompt =没有失败:Microsoft.AspNetCore.Server.Kestrel [13]连接ID“ 0HLAKEGSHERH7”,请求ID“ 0HLAKEGSHERH7:00000002”:应用程序引发了未处理的异常。System.InvalidOperationException:没有配置IAuthenticationSignInHandler来处理方案的登录:Bearer 在Microsoft.AspNetCore.Authentication.AuthenticationService.d__13.MoveNext()处-从上一个引发异常的位置开始的堆栈跟踪-在System.Runtime.CompilerServices处的System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()处。 Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler d__12.MoveNext()上的TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)-从上次引发异常的位置开始的堆栈跟踪-在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext()上的System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)---从上一个引发异常的位置开始的堆栈跟踪---在系统上。System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)的Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.d__3.MoveNext()的堆栈任务-从上一个位置开始的堆栈跟踪在Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame`1的System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)的System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()处引发了异常.d__2.MoveNext()MoveNext()-从上一个引发异常的位置开始的堆栈跟踪--在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()在Microsoft.AspNetCore .Server.Kestrel.Core.Internal.Http.Frame`1.d__2.MoveNext()MoveNext()-从上一个引发异常的位置开始的堆栈跟踪--在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()在Microsoft.AspNetCore .Server.Kestrel.Core.Internal.Http.Frame`1.d__2.MoveNext()

  1. 为什么我得到:没有配置IAuthenticationSignInHandler来处理方案的登录:Bearer,这如何解决?
  2. 如何在ExternalLoginCallback操作中检索用户信息?使用默认的mvc模板,就像操作一样简单:var info = await _signInManager.GetExternalLoginInfoAsync(); 但我没有使用登录管理器。
  3. 我根本没有找到任何有关此文档的信息,当然,如果不使用内置的巨型dumbo asp.net身份,我不是唯一需要外部身份验证的人吗?如果您是比我更好的Googler,请指出正确的方向!

Ref*_*eft 7

解决:

没有将IAuthenticationSignInHandler配置为处理方案的登录:Bearer

我必须添加一个cookie处理程序,该处理程序将临时存储外部身份验证的结果,例如,外部提供程序发送的声明。这是必要的,因为在完成外部身份验证过程之前,通常涉及几个重定向。

启动

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o =>
{
    o.TokenValidationParameters = tokenValidationParameters;
})
.AddCookie()
.AddGoogle(googleOptions =>
{
    googleOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    googleOptions.ClientId = "x";//Configuration["Authentication:Google:ClientId"];
    googleOptions.ClientSecret = "x";//Configuration["Authentication:Google:ClientSecret"];
    //googleOptions.CallbackPath = "/api/authentication/externalauthentication/signin-google";
});
Run Code Online (Sandbox Code Playgroud)

这里的重要部分是CookieAuthenticationDefaults.AuthenticationScheme。这是一个字符串常量,用于存储“ Cookies”。虽然我们可以在代码中直接使用字符串“ Cookies”,但使用预设常量会更安全。这是AddCookies默认情况下赋予该功能的身份验证方案名称。它可以帮助您参考cookie身份验证。

现在是时候从回调操作中外部认证提供的声明中检索用户信息了。

控制者

[AllowAnonymous]
[HttpPost(nameof(ExternalLogin))]
public IActionResult ExternalLogin(ExternalLoginModel model)
{
    if (model == null || !ModelState.IsValid)
    {
        return null;
    }

    var properties = new AuthenticationProperties { RedirectUri = _authenticationAppSettings.External.RedirectUri };

    return Challenge(properties, model.Provider);
}

[AllowAnonymous]
[HttpGet(nameof(ExternalLoginCallback))]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
    //Here we can retrieve the claims
    var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    return null;
}
Run Code Online (Sandbox Code Playgroud)

瞧!现在,我们可以使用一些用户信息!

在此处输入图片说明

有用的链接

http://docs.identityserver.io/en/latest/topics/signin_external_providers.html

  • 关于您的“YourCustomScheme”,您不必使用它。默认情况下它设置为“Cookies”。因此,您可以使用 `googleOptions.SignInScheme = "Cookies"` 并将 `AddCookie()` 留空 (2认同)