为什么在使用 ASP.NET Identity Core 时 OAuth 会失败?

Why does OAuth fail when using ASP.NET Identity Core?

我有一个 ASP.NET 核心 2.x 项目,配置如下:

services
  .AddAuthentication(options => options.DefaultScheme = CookieAuthenticaitonDefaults.AuthenticationScheme)
  .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddFacebook(ConfigureFacebook);

不出所料,当我从我的一个行为中调用时:

return Challenge(new AuthenticationProperties { RedirectUri = "/test" }, "Facebook");

... 然后,我通过 Facebook OAuth 序列进行导航。当我回到我的应用程序时,HttpContext.User.Identity 填充了相关详细信息:

这一切都很好,符合预期。但是,如果我将以下内容添加到我的应用程序配置中

services.AddIdentity<MyUserType, MyRoleType>()
  .AddEntityFrameworkStores<MyDbContext>();

突然之间,OAuth 流程以 User.Identity 匿名结束,没有任何其他更改。如果我们钻入 IdentityServiceCollectionExtensions.cs,我们会发现:

options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme; options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme;

除其他外...

这是怎么回事?为什么身份会干扰 Cookie 进程,从 OAuth 提供程序返回用户的正确方法是什么?

为了结合 OAuth 和 Asp.Net Core Identity,您需要配置 facebookOptions.SignInSchemeCookieAuthenticationDefaults.AuthenticationScheme

试试下面的代码:

services
    .AddAuthentication(options => options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddFacebook(facebookOptions =>
    {
        facebookOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        facebookOptions.AppId = "xx";
        facebookOptions.AppSecret = "xxx";
    });

结合使用 ASP.NET Identity 和 OAuth 时,需要注意以下几点:

配置服务:

不再需要添加 AddCookie(CookieAuthenticationDefaults.AuthenticationScheme),因为 Identity 添加了自己的 cookie 处理程序。

将外部用户作为 ClaimsPrincipal:

如果要在 HttpContext.User 下填充外部用户,请执行以下操作:

.AddFacebook(options => {
    options.SignInScheme = IdentityConstants.ApplicationScheme;
})

在您的挑战 AuthenticationProperties 中被重定向到 RedirectUri 后,您的 HttpContext.User 将被填充。

获取外部用户 ExternalLoginInfo:

如果您需要了解有关用户的信息,例如:

,这是首选
  1. 他们来自哪个供应商?
  2. 他们在提供商上的唯一密钥是什么?

您的服务应该像这样配置:

services.AddAuthentication()
    .AddFacebook(options =>
    {
        options.AppId = "";
        options.AppSecret = "";
    });

services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<MyDbContext>();

在您的登录控制器中,将 SignInManager<TUser> 注入:

public DefaultController(SIgnInManager<IdentityUser> signInManager)

并在您的挑战行动中,使用 ConfigureExternalAuthenticationProperties 获得挑战属性:

public IActionResult LoginExternal() {
    var props = SignInManager.ConfigureExternalAuthenticationProperties("Facebook", "/");
    return Challenge(props, "Facebook");
}

在您的 return 操作中,使用 GetExternalLoginInfoAsync 获取有关用户的外部详细信息:

public async Task<IActionResult> LoginCallback() {
    var loginInfo = await SignInManager.GetExternalLoginInfoAsync();
    // This object will tell you everything you need to know about the incoming user.
}