Получить электронную почту пользователя из Mastodon API через OAuth

Можно ли получить электронную почту пользователя через Mastodon Api? Я работаю над добавлением аутентификации OAuth через Mastodon Api, но, похоже, получаю только"id"и"display_name"с использованием"/api/v1/accounts/verify_credentials"конечная точка. Я не вижу свойство, возвращенное для электронной почты, поэтому в настоящее время просто использую"acct"параметр. я использую оба"read:accounts"и"admin:read:accounts"масштабы. Это для приложения NetCore.

                  builder.Services.AddAuthentication()
                .AddMicrosoftAccount("Microsoft", "Microsoft", microsoftOptions =>
                {
                    microsoftOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    microsoftOptions.ClientId = _appSettings.Authentication.Microsoft.ClientId;
                    microsoftOptions.ClientSecret = _appSettings.Authentication.Microsoft.ClientSecret;
                })
                .AddGoogle("Google", "Google", googleOptions =>
                {
                    googleOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    googleOptions.ClientId = _appSettings.Authentication.Google.ClientId;
                    googleOptions.ClientSecret = _appSettings.Authentication.Google.ClientSecret;
                })
                .AddGitHub("GitHub", "GitHub", githubOptions =>
                {
                    githubOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    githubOptions.ClientId = _appSettings.Authentication.GitHub.ClientId;
                    githubOptions.ClientSecret = _appSettings.Authentication.GitHub.ClientSecret;
                })
                .AddOAuth("Fosstodon", "Fosstodon", fosstodonOptions =>
                 {
                     fosstodonOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                     fosstodonOptions.ClientId = _appSettings.Authentication.Fosstodon.ClientId;
                     fosstodonOptions.ClientSecret = _appSettings.Authentication.Fosstodon.ClientSecret;
                     fosstodonOptions.CallbackPath = new PathString("/signin-fosstodon");

                     fosstodonOptions.AuthorizationEndpoint = _appSettings.Authentication.Fosstodon.AuthorizationEndpoint;
                     fosstodonOptions.TokenEndpoint = _appSettings.Authentication.Fosstodon.TokenEndpoint;
                     fosstodonOptions.UserInformationEndpoint = _appSettings.Authentication.Fosstodon.UserInformationEndpoint;

                     fosstodonOptions.SaveTokens = true;
                     fosstodonOptions.Scope.Add("read:accounts");
                     fosstodonOptions.Scope.Add("admin:read:accounts");

                     fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
                     fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
                     fosstodonOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");

                     fosstodonOptions.Events = new OAuthEvents
                     {
                         OnCreatingTicket = async context =>
                         {
                             var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
                             request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                             request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);

                             var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
                             response.EnsureSuccessStatusCode();

                             var user = JObject.Parse(await response.Content.ReadAsStringAsync());

                             var identifier = user.Value<string>("id")?.Clean();
                             if (!string.IsNullOrEmpty(identifier))
                             {
                                 context.Identity?.AddClaim(new Claim(
                                     ClaimTypes.NameIdentifier, identifier,
                                     ClaimValueTypes.String, context.Options.ClaimsIssuer));
                             }

                             var userName = user.Value<string>("display_name")?.Clean();
                             if (!string.IsNullOrEmpty(userName))
                             {
                                 context.Identity?.AddClaim(new Claim(
                                     ClaimTypes.Name, userName,
                                     ClaimValueTypes.String, context.Options.ClaimsIssuer));
                             }

                             var userEmail = user.Value<string>("acct")?.Clean();
                             if (!string.IsNullOrEmpty(userEmail))
                             {
                                 context.Identity?.AddClaim(new Claim(
                                     ClaimTypes.Email, userEmail,
                                     ClaimValueTypes.String, context.Options.ClaimsIssuer));
                             }
                         }
                     };
                 });

Действительно хочу знать, является ли их конечная точка, которая вернет текущий адрес электронной почты пользователя. Я просмотрел документацию Mastodon Api , но не увидел и не указал на это.

1 ответ

Обнаружено, что невозможно получить электронную почту пользователя через Mastodon Api. Вместо этого решил обработать эту ситуацию в процессе регистрации потока аутентификации приложения. В основном проверьте, существует ли пользователь с данным адресом электронной почты. Если это так, удалите пользователя с автоматической подготовкой и добавьте информацию о внешнем поставщике существующему пользователю. Позже будет отправлено подтверждение электронной почты на указанный адрес электронной почты, чтобы кто-то не мог украсть учетную запись пользователя при регистрации.

              /// <summary>
        /// Handle postback from new registration
        /// </summary>
        /// <returns>IActionResult</returns>
        [AllowAnonymous]
        [HttpPost("Registration/New")]
        [HttpPost("Registration/New/{id?}")]
        [ValidateAntiForgeryToken]
        public virtual async Task<IActionResult> New([Bind(RegistrationViewModel.BindProperties)] RegistrationViewModel model, [FromForm(Name = "Button")] string button)
        {
            // Check if cancled
            if (button.Clean() != "submit")
                return RedirectToAction("Index", "Home");

            // Check email is valid
            if (!model.Email.Clean().IsValidEmail())
                ModelState.AddModelError(nameof(model.Email), _sharedLocalizer["ErrorMessage.Invalid"]);

            if (ModelState.IsValid)
            {
                // setup results
                IdentityResult identityResult = new IdentityResult();

                // Check for existing user
                ApplicationUser user = await _userManager.FindByEmailAsync(model.Email.Clean());
                if (user != null)
                {
                    if (user.Id != model.Id.Clean())
                    {
                        ApplicationUser removeUser = await _userManager.FindByIdAsync(model.Id.Clean());
                        if (removeUser != null)
                        {
                            identityResult = await _userManager.DeleteAsync(removeUser);
                            if (!identityResult.Succeeded) throw new Exception(identityResult.Errors.First().Description);
                        }
                    }
                }
                else
                {
                    user = await _userManager.FindByIdAsync(model.Id.Clean());
                    if (user == null)
                        throw new KeyNotFoundException($"[Key]: {nameof(model.Id)} [Value]: {model.Id}");
                }

                user.DisplayName = model.DisplayName.Clean();
                user.UserName = model.Email.Clean();
                user.NormalizedUserName = model.Email.Clean();
                user.Email = model.Email.Clean();
                user.NormalizedEmail = model.Email.Clean();

                identityResult = await _userManager.UpdateAsync(user);
                if (!identityResult.Succeeded) throw new Exception(identityResult.Errors.First().Description);

                if (!string.IsNullOrEmpty(model.ProviderUserId.Clean()))
                {
                    var userLogins = await _userManager.GetLoginsAsync(user);
                    UserLoginInfo? userLogin = userLogins
                        .Where(x => x.LoginProvider == model.Provider.Clean())
                        .Where(x => x.ProviderKey == model.ProviderUserId.Clean())
                        .FirstOrDefault();

                    if (userLogin == null)
                    {
                        identityResult = await _userManager.AddLoginAsync(user, new UserLoginInfo(model.Provider.Clean(), model.ProviderUserId.Clean(), model.Provider.Clean()));
                        if (!identityResult.Succeeded) throw new Exception(identityResult.Errors.First().Description);
                    }
                }
            }

            return View(model);
        }
Другие вопросы по тегам