c# - 谷歌认证获取用户头像

标签 c# asp.net asp.net-core asp.net-identity google-oauth

如果用户通过 google 进行身份验证,我需要获取他的个人资料照片。

如果用户通过 facebook 进行身份验证,我会使用以下代码获取他的个人资料图片:

var info = await _signInManager.GetExternalLoginInfoAsync();
var identifier = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier); 
var picture = $"https://graph.facebook.com/{identifier}/picture"; // 3

那么,如果用户通过 google 进行身份验证,我需要在第 3 行中使用哪个代码来获取用户的个人资料图片?

最佳答案

获取用户头像,完整解决方案。

堆栈:
Asp Net Identity 4 v4 + Asp Net Identity + Google People Api

步骤

1。准备工作

1.1 我正在使用默认的 HttpClient 生成对 Google API 的 HTTP 请求
1.2 安装 NUGET System.Net.Http.Json 以简化序列化。 1.3 使用 [json to c#] 工具,创建这样的 DTO:


/// <summary>
    /// 🟡 official docs.
    /// https://developers.google.com/people/api/rest/v1/people#Person.Photo
    /// </summary>
    public class PeopleApiPhotos    {
        
        public string resourceName { get; set; } 
        public string etag { get; set; } 
        public List<Photo> photos { get; set; }
        
        public class Source    {
            public string type { get; set; } 
            public string id { get; set; } 
        }

        public class Metadata    {
            public bool primary { get; set; } 
            public Source source { get; set; } 
        }

        public class Photo    {
            public Metadata metadata { get; set; } 
            public string url { get; set; } 
        }
    }

2。 Identity Server:当用户确认外部信息数据时,发送http get请求,获取头像图片url:

具有 Asp Net Identity 的身份服务器 > 登录 > OnPostConfirmationAsync:完整方法


public async Task < IActionResult > OnPostConfirmationAsync(string returnUrl = null) {
  returnUrl = returnUrl ? ?Url.Content("~/");
  // Get the information about the user from the external login provider
  var info = await _signInManager.GetExternalLoginInfoAsync();
  if (info == null) {
    ErrorMessage = "Error loading external login information during confirmation.";
    return RedirectToPage("./Login", new {
      ReturnUrl = returnUrl
    });
  }

  // try to get profile picture
  string pictureUri = string.Empty;

  if (info.LoginProvider.ToLower() == "google") {
    var httpClient = _httpClientFactory.CreateClient();
    string peopleApiKey = _configuration["GoogleApiKey:PeopleApiKey"];;
    var googleAccountId = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
    var photosResponse = await httpClient.GetFromJsonAsync < PeopleApiPhotos > (
    $ "https://people.googleapis.com/v1/people/{googleAccountId}?personFields=photos&key={peopleApiKey}");
    pictureUri = photosResponse ? .photos.FirstOrDefault() ? .url;
  }

  if (ModelState.IsValid) {
    // Cria usuário
    var user = new AppUser {
      UserName = Input.Email,
      Email = Input.Email,
      FirstName = Input.FirstName,
      LastName = Input.LastName,
      ProfilePictureUrl = pictureUri
    };

    var result = await _userManager.CreateAsync(user);
    if (result.Succeeded) {
      result = await _userManager.AddLoginAsync(user, info);
      if (result.Succeeded) {
        _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);

        var userId = await _userManager.GetUserIdAsync(user);
        var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
        code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
        var callbackUrl = Url.Page("/Account/ConfirmEmail", pageHandler: null, values: new {
          area = "Identity",
          userId = userId,
          code = code
        },
        protocol: Request.Scheme);

        await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $ "Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

        // If account confirmation is required, we need to show the link if we don't have a real email sender
        if (_userManager.Options.SignIn.RequireConfirmedAccount) {
          return RedirectToPage("./RegisterConfirmation", new {
            Email = Input.Email
          });
        }

        await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider);

        return LocalRedirect(returnUrl);
      }
    }
    foreach(var error in result.Errors) {
      ModelState.AddModelError(string.Empty, error.Description);
    }
  }

  ProviderDisplayName = info.ProviderDisplayName;
  ReturnUrl = returnUrl;
  return Page();
}

2.1 Identity Server with Asp Net Identity > Login > OnPostConfirmationAsync: HIGHLIGHT:

❗️这只是上面完整方法的一小部分。

检查外部提供商是否为 Google,并使用 [NameIdentifier] 和 [Google Api Key] 访问People Endpoint


// try to get profile picture
string pictureUri = string.Empty;

if (info.LoginProvider.ToLower() == "google") {
  var httpClient = _httpClientFactory.CreateClient();
// ApiKey can get generated in [Google Developers Console](https://console.developers.google.com/apis/credentials).
  string peopleApiKey = _configuration["GoogleApiKey:PeopleApiKey"];;
  var googleAccountId = info.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
  var photosResponse = await httpClient.GetFromJsonAsync < PeopleApiPhotos > (
  $ "https://people.googleapis.com/v1/people/{googleAccountId}?personFields=photos&key={peopleApiKey}");
  pictureUri = photosResponse ? .photos.FirstOrDefault() ? .url;
}

3。身份服务器 > 配置文件服务实现:


public async Task GetProfileDataAsync(ProfileDataRequestContext context) {
  var sub = context.Subject.GetSubjectId();
  var user = await _userManager.FindByIdAsync(sub);
  var principal = await _claimsFactory.CreateAsync(user);

  var claims = principal.Claims.ToList();

  claims.Add(new Claim(JwtClaimTypes.GivenName, user.FirstName));
  claims.Add(new Claim(JwtClaimTypes.FamilyName, user.LastName));

  // Insert a new claim, that gets ProfilePictureUrl persisted in my app user in database.
  claims.Add(new Claim(JwtClaimTypes.Picture, user.ProfilePictureUrl));

  context.IssuedClaims = claims;
}

4。在 ReactJS 前端访问配置文件用户:

为了在前端获取用户个人资料数据,我正在使用 OidcClient-js


// here i'm using oidc-client.js
// user object is loaded with user full data.
let profilePictureUrl = user.profile.picture;

showing profile picture successfully loaded from Google People API


感谢@DaImTo 的回复。

关于c# - 谷歌认证获取用户头像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62703154/

相关文章:

c# - 为什么要为这个配置类创建一个接口(interface)呢?

c# - 将 TextReader 流式传输到文件

c# - 可以处理WP7.1 中的所有MouseMove 事件吗?

c# - 如何扩展 WinForm 的 Dispose 方法?

JavaScript 断点在 Visual Studio 2008 中不再起作用?

c# - 在我检查谷歌浏览器中的元素之前,一些文本不会出现

c# - 将页眉和页脚图像添加到 PDF : Header image doesn't show, 页脚被放大

c# - 减少/删除 ASP.NET Core 中重复的业务逻辑检查

c# - 为什么 Application Insights 依赖关系时间线存在间隙?

c# - 使用 DryWetMidi 从 MIDI 文件中读取每个音符(音符、力度、长度)