Создание файлов cookie для частичной авторизации для внешней аутентификации

Недавно я реализовал 2FA для своего веб-API с помощью Identity Server 3. Все работает так, как ожидалось, если логин сделан локально (с использованием IUserService). Теперь, я хочу, чтобы иметь возможность сделать это логин, выпустив частичный файл cookie для входа. Это означает, что у меня есть метод API (POST), который позволит пользователям делать частичный вход без входа на главную страницу. Чтобы выпустить файл cookie для проверки подлинности, это то, что я делаю (на основе метода IS3 Extensions):

_owinContext.Environment.IssueLoginCookie(new AuthenticatedLogin
{
      IdentityProvider = Constants.ExternalAuthenticationType,
      Subject = userId,
      Name = identityId,
      Claims = new[] { new Claim(ClaimTypes.NameIdentifier, identityId) },
      AuthenticationMethod = Constants.AuthenticationMethods.TwoFactorAuthentication
});

После этого я перенаправляю пользователя обратно на страницу входа в систему, и он полностью входит в приложение, минуя шаг 2FA. Я надеялся, что это заставит пользователя частично войти в систему, но вместо этого полностью выполнит вход пользователя.

Примечание. Способ реализации двух факторов основан на методе AuthenticateLocalAsync из IUserService. Здесь я обновляю AuthenticateResult, чтобы использовать конструктор с пути перенаправления. Метод API не вызывает IUserService. Это простое решение для файлов cookie для входа.

Edit: Итак, после проверки внутренней реализации IdentityServer3 я теперь могу заставить пользователя пройти через экраны 2FA. Теперь проблема заключается в том, что частичный вход в систему является успешным (совпадают коды аутентификации). Я перенаправляю пользователя на URL-адрес резюме, и это приводит к странице с ошибкой 500 (при этом не отображаются исключения или журналы). Если это происходит при обычном входе в страницу, все работает.

Обращайтесь с запросом пользователя на вход:

var messageId = clientIdentifier;

var claims = new List<Claim>();
(...)

var authenticationContext = new ExternalAuthenticationContext
{
    ExternalIdentity = new ExternalIdentity() { Provider = "API", Claims = claims },
};

await _userService.AuthenticateExternalAsync(authenticationContext);
var authResult = authenticationContext.AuthenticateResult;

var ctx = new PostAuthenticationContext
{
    AuthenticateResult = authResult
};

var id = authResult.User.Identities.FirstOrDefault();
var props = new AuthenticationProperties();
var resumeId = CryptoRandom.CreateUniqueId();

var resumeLoginUrl = _owinContext.GetPartialLoginResumeUrl(resumeId);
var resumeLoginClaim = new Claim(Constants.ClaimTypes.PartialLoginReturnUrl, resumeLoginUrl);
id.AddClaim(resumeLoginClaim);
id.AddClaim(new Claim(GetClaimTypeForResumeId(resumeId), messageId));

// add url to start login process over again (which re-triggers preauthenticate)
var restartUrl = _owinContext.GetPartialLoginRestartUrl(messageId);
id.AddClaim(new Claim(Constants.ClaimTypes.PartialLoginRestartUrl, restartUrl));

_owinContext.Authentication.SignIn(props, id);

// Sends the user to the 2FA pages (where he needs to insert the validation code).
// At this point the user is successfuly partially logged in.
var redirectUrl = GetRedirectUrl(authResult);
return Redirect(redirectUrl);

После ввода кода 2FA пользователь должен полностью войти в систему после ввода URL-адреса резюме:

if (isAuthCodeValid)
{
    var resumeUrl = await owinContext.Environment.GetPartialLoginResumeUrlAsync();

    // Redirects the user to resume url. This is not working if authentication is done by API but is works with normal local authentication.
   // With API it redirects to a page which eventually will have 500 error (no logs or exceptions being shown)
    return Redirect(resumeUrl);
}

Вы, ребята, когда-либо пытались сделать что-то подобное или если это возможно?

Ответы