最近我使用 IdentityServer3 为我的 WebAPI 实现了 2FA。如果在本地登录(使用IUserService),一切都会按预期进行。现在,我希望能够通过发出部分登录 cookie 来进行此登录。这意味着我有一个 API 方法 (POST),它可以让用户在不进入主页的情况下进行部分登录。要发出身份验证 cookie,这就是我所做的(基于 IdentityServer3 扩展方法):
_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。
编辑: 所以在检查 IdentityServer3 内部实现之后,我现在可以让用户通过 2FA 屏幕。现在的问题是,当部分登录成功(验证码匹配)时,我将用户重定向到简历 URL 并导致 500 错误页面(没有抛出异常或显示日志)。如果在正常页面登录时发生这种情况,则一切正常。
处理用户 post 请求登录:
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);