【问题标题】:Google Authentication get user profile picture谷歌认证获取用户头像
【发布时间】:2020-07-02 18:50:09
【问题描述】:

如果用户是通过谷歌认证的,我需要获取他的头像。

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

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

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

【问题讨论】:

  • 在为用户请求授权时,需要请求profile范围。不幸的是,Facebook 代码不会连接到谷歌。尝试使用 google .net 客户端库。我认为通过 google 进行身份验证不会是三行代码
  • @DalmTo 我知道如何通过 google 进行身份验证,我想知道如何获取已通过身份验证的用户的头像
  • 您是否按照我的建议尝试了 People api?
  • @DalmTo developers.google.com/people/v1/how-tos/… 这里没有关于个人资料图片的信息,只有关于电子邮件、年龄等的信息

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


【解决方案1】:

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

堆栈:
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: FULL METHOD


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 带有 Asp Net Identity 的身份服务器 > 登录 > 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;


感谢@DaImTo 的回复。

【讨论】:

    【解决方案2】:

    People.get 方法返回一个person object,其中包含

    您的用户需要使用配置文件范围进行身份验证。

    原始 http 请求

    GET https://people.googleapis.com/v1/people/me?personFields=photos HTTP/1.1
    
    Authorization: Bearer [YOUR_ACCESS_TOKEN]
    Accept: application/json
    

    回复

    {
      "resourceName": "people/117200475532672775346",
      "etag": "%EgQBAzcuGgQBAgUHIgxHcHNCRHZycjVkZz0=",
      "photos": [
        {
          "metadata": {
            "primary": true,
            "source": {
              "type": "PROFILE",
              "id": "1172004755672775346"
            }
          },
          "url": "https://lh3.googleusercontent.com/a-/AOh14GhroCYJp2P9xeYeYk1npchBPK-zbtTxzNQo0WAHI20=s100"
        },
        {
          "metadata": {
            "source": {
              "type": "CONTACT",
              "id": "3faa96eb0baa4be"
            }
          },
          "url": "https://lh6.googleusercontent.com/-vuhaM1mUvwE/VFOBzFDW-TI/AAAAAAAAAAA/izR9rgfDIyoVoHd7Mq_OJmdbwjhEnfhEQCOQCEAE/s100/photo.jpg"
        }
      ]
    }
    

    注意:您也可以从 userinfo 端点获取此信息,但 Google 不保证他们会在您每次提出请求时发送声明,因此 IMO 最好通过 people api。

    【讨论】:

    • 在哪里可以找到GET https://people.googleapis.com/v1/people/me?personFields=photos&amp;key=[YOUR_API_KEY] HTTP/1.1 的 API KEY?
    • 你确定这是获取用户头像的唯一方法吗?对于 facebook,它只有 1 行代码,但这看起来要复杂得多。
    • 是否可以在没有API_KEY 的情况下获取个人资料图片并使用user_id 代替它?
    • 只要您有可以发送到请求的访问令牌。您还需要使用配置文件范围对用户进行身份验证。这是用户需要对您的应用程序进行身份验证的 google 而不是 facebook。无论如何,您现在都有办法获取 Google 用户 ID,除非您已通过用户身份验证,而且我认为用户 ID 不会以这种方式与图片相关联。
    • @Roomey ,API KEY可以在这个链接中创建:console.developers.google.com/apis/credentials
    猜你喜欢
    • 1970-01-01
    • 2014-11-02
    • 2015-01-13
    • 2023-03-05
    • 2016-02-10
    • 1970-01-01
    • 2014-01-16
    • 2011-07-17
    相关资源
    最近更新 更多