#asp.net-core #oauth-2.0 #asp.net-identity #single-page-application #openiddict
#asp.net-core #oauth-2.0 #asp.net-identity #одностраничное приложение #openiddict
Вопрос:
TL; DR
Вопрос: как реализовать социальный вход в систему (поток авторизации OAuth2) с существующим приложением SPA / Web API, основанным на идентификации, пользователе / пароле, аутентификации токена на предъявителя?
У меня есть существующее приложение, которое имеет:
Серверная часть: веб-API .Net Core 2 с настроенными службами идентификации и OpenIddict, с рабочим процессом аутентификации на основе запроса пользователя / пароля для токена на предъявителя.
Пользователи хранятся с идентификатором (AspNetUsers).
Часть кода Startup.cs
// Register the OpenIddict services.
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>();
})
.AddServer(options =>
{
options.UseMvc();
options.EnableTokenEndpoint("/connect/token");
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
options.AcceptAnonymousClients();
options.RegisterScopes(
OpenIdConnectConstants.Scopes.OpenId,
OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Phone,
OpenIdConnectConstants.Scopes.Profile,
OpenIdConnectConstants.Scopes.OfflineAccess,
OpenIddictConstants.Scopes.Roles);
})
.AddValidation();
.
Интерфейс: приложение SPA Angular 7, которое использует этот серверный API и авторизацию токенов
Таким образом, в основном текущая настройка заключается в том, что пользователь вводит пользователя / пароль в SPA, который вызывает /connect/token
конечную точку сервера, которая проверяет учетные данные и генерирует токен для клиента.
И теперь мне нужно интегрировать социальный вход в систему (поток авторизации OAuth2), чтобы
- пользователь выбирает вход с помощью провайдера,
- перенаправляется на страницу авторизации провайдеров,
- перенаправляется обратно в мое приложение, которое
- необходимо создать идентификатор пользователя и сохранить данные Identity UserLoginInfo и
- предоставьте мой токен приложения, чтобы пользователь мог войти в систему.
Я понимаю поток авторизации OAuth2, который должен запрашивать код авторизации, а затем обменивать код авторизации на токен доступа для этого провайдера. Я также знаю, что этот поток должен использовать серверную часть, поскольку он использует конфиденциальную информацию, такую как client_secret, которая не может быть сохранена на стороне клиента.
Но в какой-то момент пользователю необходимо взаимодействовать с интерфейсом, поэтому подключение этих частей кажется очень сложным, учитывая, что это широко используемые технологии. Все практические примеры, которые я нашел в Google, были с использованием приложения .Net Core MVC. Я также нашел эту статью ASP.NET Предварительный просмотр ядра 3.0 4 — Аутентификация и авторизация для СПА-центров, которые кажутся многообещающими, но все еще находятся в предварительном просмотре 4.
Я уже создал приложения для социальных сетей, и у меня есть client_id, client_secret. Также зарегистрировал мои перенаправляющие URL-адреса.
То, что я безуспешно пытался, было:
- Во внешнем интерфейсе пользователь выбирает вход в систему с помощью социального провайдера,
- Пользователь перенаправляется на страницу авторизации провайдера, аутентифицируется и
- перенаправляется от провайдера на мой URL-адрес интерфейса (
redirect_uri
) с кодом провайдера, а затем - мой интерфейс вызывает мою серверную
/connect/token
существующую конечную точку, передавая выбранного поставщика и полученный код, конечная точка была запрограммирована на получение поставщика и кода также, затем - мой сервер вызывает отправку URL-адреса get accessToken провайдером
"grant_type", "authorization_code"
"code", code
"redirect_uri", "https://same_frontend_host/same/path"
"client_id", providerClientId
"client_secret", providerSecret
и получаетStatusCode: 401, ReasonPhrase: 'Unauthorized'
ответ
Что я делаю не так? Это было действительно трудное время, чтобы заставить это работать.
Что сработало, но это не то, что мне нужно
Неявный 2-шаговый процесс авторизации с использованием интерфейса для вызовов аутентификации поставщика и внутреннего вызова для получения моего токена на предъявителя и создания идентификатора пользователя. С помощью этой настройки пользователь успешно вошел в систему с помощью социального провайдера, к сожалению, это не то, что мне нужно
Редактировать:
Сделал диаграмму того, что реализовано, на шаге 5/6 происходит сбой с StatusCode: 401, ReasonPhrase: 'Unauthorized'
, и дальнейшие шаги не завершены.
Комментарии:
1. смогли ли вы найти решение, я столкнулся с аналогичной проблемой
Ответ №1:
Описанный вами процесс в значительной степени соответствует «Междоменному коду авторизации», потоку подключения OpenID, который никогда не был стандартизирован.
Я бы не рекомендовал использовать такой нестандартный вариант. Вместо этого рассмотрите возможность настройки вашего потока, чтобы ваш JS-клиент взаимодействовал исключительно с вашим собственным сервером авторизации, вместо того, чтобы запускать поток, перенаправляя клиент агента пользователя внешнему поставщику.
Ключевая идея здесь заключается в том, что ваш собственный сервер авторизации должен инициировать первоначальную связь с внешним провайдером (т. Е. он должен сформировать запрос на авторизацию и перенаправить ваших пользователей на конечную точку авторизации внешнего провайдера) и обработать последнюю часть: ответ на авторизацию обратного вызова. Для этого я бы рекомендовал использовать обработчики OAuth2 / OIDC, поставляемые с ASP.NET Ядро (есть поставщики для Google, Facebook и многих других)
Конечно, это не означает, что ваш JS-клиент не может отправить подсказку о внешнем поставщике, которого пользователь должен использовать для аутентификации. Это то, с чем вы можете легко справиться в своем контроллере авторизации. Вот пример:
public class AuthorizationController : Controller
{
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
private readonly SignInManager<ApplicationUser> _signInManager;
public AuthorizationController(
IAuthenticationSchemeProvider authenticationSchemeProvider,
SignInManager<ApplicationUser> signInManager)
{
_authenticationSchemeProvider = authenticationSchemeProvider;
_signInManager = signInManager;
}
[HttpGet("~/connect/authorize")]
public async Task<IActionResult> Authorize(OpenIdConnectRequest request)
{
Debug.Assert(request.IsAuthorizationRequest(),
"The OpenIddict binder for ASP.NET Core MVC is not registered. "
"Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");
if (!User.Identity.IsAuthenticated)
{
// Resolve the optional provider name from the authorization request.
// If no provider is specified, call Challenge() to redirect the user
// to the login page defined in the ASP.NET Core Identity options.
var provider = (string) request.GetParameter("identity_provider");
if (string.IsNullOrEmpty(provider))
{
return Challenge();
}
// Ensure the specified provider is supported.
var schemes = await _authenticationSchemeProvider.GetAllSchemesAsync();
if (!schemes.Any(scheme => scheme.Name == provider))
{
return Challenge();
}
// When using ASP.NET Core Identity and its default AccountController,
// the user must be redirected to the ExternalLoginCallback action
// before being redirected back to the authorization endpoint.
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider,
Url.Action("ExternalLoginCallback", "Account", new
{
ReturnUrl = Request.PathBase Request.Path Request.QueryString
}));
return Challenge(properties, provider);
}
// ...
}
}
Комментарии:
1. Может быть слишком поздно… но он использует
WebApi
который не может инициировать поток…