Как создать AccessToken для пользователя, который вошел в систему с внешними провайдерами
У меня есть API, реализованный ядром asp.net. Я использовал OpenIddict для создания токена доступа и обновления токена для пользователей, которые зарегистрировались в моем API по электронной почте и паролю. Я добавил промежуточное программное обеспечение Google (.UseGoogleAuthentication...) в свой API, и я могу успешно войти в систему с помощью Google. Мой клиент - UWP, и я использую WebAuthenticationBroker для перенаправления в Google после отправки запроса на localhost/Account/ExternalLogin/Google. когда пользователь входит в систему с помощью Google, он перенаправляется в Account/ExternalLoginConfirmation, что является тривиальным до этого момента, прежде чем он завершается с ExternalLoginConfirmation. Я хочу сгенерировать и отправить обратно токен доступа и токен обновления для пользователя, если закрывается WebAuthenticationBroker У меня нет другого способа получить токены для этого пользователя (потому что у него нет пароля и имя пользователя будет мне неизвестно). Это так:
//
// POST: /Account/
[HttpPost("ExternalLoginConfirmation")]
[AllowAnonymous]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model,
string returnUrl = null)
{
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await SignInManager.GetExternalLoginInfoAsync();
if (info == null)
return View("ExternalLoginFailure");
var user = new UserInfo { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
result = await UserManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, false);
Logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
var identity = new ClaimsIdentity(
OpenIdConnectServerDefaults.AuthenticationScheme,
OpenIdConnectConstants.Claims.Name, null);
// Add a "sub" claim containing the user identifier, and attach
// the "access_token" destination to allow OpenIddict to store it
// in the access token, so it can be retrieved from your controllers.
identity.AddClaim(OpenIdConnectConstants.Claims.Subject,
user.Id,
OpenIdConnectConstants.Destinations.AccessToken);
identity.AddClaim(OpenIdConnectConstants.Claims.Name, user.UserName,
OpenIdConnectConstants.Destinations.AccessToken);
// ... add other claims, if necessary.
var principal = new ClaimsPrincipal(identity);
var authenticateInfo = await HttpContext.Authentication.GetAuthenticateInfoAsync(info.LoginProvider);
var ticket = CreateTicketAsync(principal, authenticateInfo.Properties);
// Ask OpenIddict to generate a new token and return an OAuth2 token response.
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
//return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
//ViewData["ReturnUrl"] = returnUrl;
return BadRequest();
}
#region _helpers
private AuthenticationTicket CreateTicketAsync(ClaimsPrincipal principal,
AuthenticationProperties properties = null)
{
// Create a new authentication ticket holding the user identity.
var ticket = new AuthenticationTicket(principal, properties,
OpenIdConnectServerDefaults.AuthenticationScheme);
ticket.SetScopes(new[]
{
/* openid: */ OpenIdConnectConstants.Scopes.OpenId,
/* email: */ OpenIdConnectConstants.Scopes.Email,
/* profile: */ OpenIdConnectConstants.Scopes.Profile,
/* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess,
/* roles: */ OpenIddictConstants.Scopes.Roles
});
ticket.SetAudiences(Configuration["Authentication:OpenIddict:Audience"]);
return ticket;
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
ModelState.AddModelError(string.Empty, error.Description);
}
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
return Redirect(returnUrl);
return BadRequest();
}
#endregion
но это терпит неудачу и выдает исключение:an authorization or token response cannot be returned from this controller
Теперь, как я могу сгенерировать эти токены для пользователя?
1 ответ
Теперь, как я могу сгенерировать эти токены для пользователя?
OpenIddict намеренно запрещает вам возвращать ответы OIDC с конечных точек, не относящихся к OIDC (по очевидным причинам безопасности).
Чтобы ваш сценарий работал, вы должны перенаправить пользователей обратно в конечную точку авторизации со всеми параметрами OpenID Connect.
Конкретно, вы должны отменить все изменения, добавленные в ExternalLoginConfirmation()
(это должно вернуться RedirectToLocal(returnUrl);
) и переместить SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
часть обратно к вашему контроллеру авторизации.