Instagram OAuth GetExternalLoginInfoAsync 在 .NET Core 2.0 中始终返回 null

2024-06-28

我可以使用以下命令在 .NET Core 1 中配置 Instagram 身份验证这个图书馆 https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers,但我似乎无法让它在 .NET Core 2 中工作。

似乎没有任何 Instagram OAuth 库与 .NET Core 2.0 兼容,所以我尝试使用内置的 AddOAuth 方法。我能够毫无问题地对所有内容进行身份验证,但由于某种原因,LinkLoginCallback 中的 GetExternalLoginInfoAsync 方法始终返回 null。由于所有这些事情都发生在 AspNetCore.Authentication 中,我假设我的设置和配置不正确(或缺少某些关键内容),或者此解决方案由于其他原因而无法工作。

我在ConfigureServices 中的配置如下所示:

services.AddAuthentication().AddOAuth("Instagram", "Instagram", options =>
        {
            options.ClientId = "MYID";
            options.ClientSecret = "MYSECRET";
            options.AuthorizationEndpoint = "https://api.instagram.com/oauth/authorize/";
            options.CallbackPath = "/signin-instagram";
            options.TokenEndpoint = "https://api.instagram.com/oauth/access_token";
            options.Scope.Add("basic");
            options.ClaimsIssuer = "Instagram";
            options.UserInformationEndpoint = "https://api.instagram.com/v1/users/self";
        });

有人能够在 .NET Core 2.0 中成功通过 Instagram 进行身份验证吗?任何帮助将不胜感激!


不是专门针对 Instagram,但我使用与上面类似的设置为 Twitch 进行了自定义 OAuth 验证。

我从 GetExternalLoginInfoAsync 中收到了相同的 Null 错误,并且我必须执行许多步骤才能使其正常工作。

最后,我通过查看此处找到的 GetExternalLoginInfoAsync 方法的源代码发现了问题 -Microsoft.AspNetCore.Identity.SignInManager.cs https://github.com/aspnet/Identity/blob/dev/src/Microsoft.AspNetCore.Identity/SignInManager.cs#L693

  1. 我发现的第一件事实际上是在方法的第一行

    var auth = await Context.AuthenticateAsync(IdentityConstants.ExternalScheme);
    

    该方法设置为始终使用ExternalScheme 常量,因此如果您在 Startup.cs 中设置自定义 SignInScheme 调用此方法时不会使用它。将 SignInScheme 设置为默认值似乎对我也不起作用。

  2. LoginProviderKey 为空。

    if (auth?.Principal == null || items==null||!items.ContainsKey(LoginProviderKey)){return null;}
    
  3. 修复上述问题后,我发现没有设置任何声明,因此我也必须手动设置。我在另一个 Stackoverflow 问题上找到了这样的例子 -AddOAuth linkedin dotnet core 2.0 https://stackoverflow.com/a/46064936/97143

请参阅下面我的最终代码:

Startup.cs 配置 OAuth 中间件

在 Startup 中,我将 SignInScheme 设置为使用 IdentityConstants.ExternalScheme 值,并在 OnCreatingTicket 中添加客户声明设置事件。

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddOAuth("Twitch", "Twitch", o =>
              {
                  o.SignInScheme = IdentityConstants.ExternalScheme;
                  o.ClientId = "MY CLIENT ID";
                  o.ClientSecret = "MY CLIENT SECRET";
                  o.CallbackPath = "/signin-twitch";
                  o.ClaimsIssuer = "Twitch";
                  o.AuthorizationEndpoint = "https://api.twitch.tv/kraken/oauth2/authorize";
                  o.TokenEndpoint = "https://api.twitch.tv/api/oauth2/token";
                  o.UserInformationEndpoint = "https://api.twitch.tv/helix/users";
                  o.Scope.Add("openid");
                  o.Scope.Add("user:read:email");

                  o.Events = new Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents
                  {
                      OnCreatingTicket = async context =>
                      {
                          var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
                          request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
                          request.Headers.Add("x-li-format", "json");

                          var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
                          response.EnsureSuccessStatusCode();
                          var user = JObject.Parse(await response.Content.ReadAsStringAsync());

                          var data = user.SelectToken("data")[0];

                          var userId = (string)data["id"];
                          if (!string.IsNullOrEmpty(userId))
                          {
                              context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String, context.Options.ClaimsIssuer));
                          }

                          var formattedName = (string)data["display_name"];
                          if (!string.IsNullOrEmpty(formattedName))
                          {
                              context.Identity.AddClaim(new Claim(ClaimTypes.Name, formattedName, ClaimValueTypes.String, context.Options.ClaimsIssuer));
                          }

                          var email = (string)data["email"];
                          if (!string.IsNullOrEmpty(email))
                          {
                              context.Identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String,
                                  context.Options.ClaimsIssuer));
                          }
                          var pictureUrl = (string)data["profile_image_url"];
                          if (!string.IsNullOrEmpty(pictureUrl))
                          {
                              context.Identity.AddClaim(new Claim("profile-picture", pictureUrl, ClaimValueTypes.String,
                                  context.Options.ClaimsIssuer));
                          }
                      }
                  };
              });

AccountController.cs 创建挑战

当我们发出挑战时,我们还必须包含 LoginProvider 值。

public IActionResult LoginWithTwich(string returnUrl = null)
    {

        var authProperties = _signInManager.ConfigureExternalAuthenticationProperties("Twitch", returnUrl);

        return Challenge(authProperties, "Twitch");
    }

AccountController.cs 处理回调

最后,当我们处理回调时,GetExternalLoginInfoAsync 方法不再返回 null。

public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null)
    {
        ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();
        //to sign the user in if there's a local account associated to the login provider
        var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
        if (!result.Succeeded)
        {
            return RedirectToAction("ConfirmTwitchLogin", new { ReturnUrl = returnUrl });
        }
        if (string.IsNullOrEmpty(returnUrl))
        {
            return Redirect("~/");
        }
        else
        {
            return RedirectToLocal(returnUrl);
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Instagram OAuth GetExternalLoginInfoAsync 在 .NET Core 2.0 中始终返回 null 的相关文章

随机推荐