【发布时间】:2020-07-10 21:59:07
【问题描述】:
我们需要根据外部 API 对 IdentityServer4 中的用户进行身份验证。场景是这样的:
- 用户访问 Javascript 客户端应用程序并单击登录按钮以重定向到 IdentityServer 登录页面(与文档中提供的完全相同的客户端 here
用户输入他们的用户名(电子邮件)和密码
IdentityServer4 连接到外部 API 以验证凭据
用户被重定向回 JavaScript 应用程序
在使用快速入门中提供的 TestUser 时,上述过程非常完美。但是,当使用 API 时,登录页面会重置并且不会将用户重定向回 JavaScript 客户端。唯一的变化是下面的代码和 IProfileService 的自定义实现。
以下是登录操作中的自定义代码(仅显示相关部分):
var apiClient = _httpClientFactory.CreateClient("API");
var request = new HttpRequestMessage(HttpMethod.Post, "/api/auth");
var loginModel = new LoginModel
{
Email = model.Email,
Password = model.Password
};
var content = new StringContent(JsonConvert.SerializeObject(loginModel),
Encoding.UTF8, "application/json");
request.Content = content;
HttpResponseMessage result = await apiClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
var loginStatus = JsonConvert.DeserializeObject<ApiLoginStatus>(
await result.Content.ReadAsStringAsync());
if (loginStatus.LoginSuccess)
{
await _events.RaiseAsync(new UserLoginSuccessEvent(model.Email, model.Email, loginStatus.Name, clientId: context?.ClientId));
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
var user = new IdentityServerUser(loginStatus.SubjectId)
{
DisplayName = loginStatus.Name
};
await HttpContext.SignInAsync(user, props);
if (context != null)
{
if (await _clientStore.IsPkceClientAsync(context.ClientId))
{
return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
}
return Redirect(model.ReturnUrl);
}
代码实际上命中了返回 View() 路径,但由于某种原因它重置并再次显示登录页面。
Startup.cs 中的代码:
var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.Ids)
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients)
.AddProfileService<ProfileService>()
.AddDeveloperSigningCredential();
ProfileService.cs 中的代码:
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var profile = await GetUserProfile(context.Subject.GetSubjectId());
var claims = new List<Claim>
{
new Claim(ClaimTypes.Email, profile.Email),
new Claim(ClaimTypes.Name, profile.Name)
};
context.IssuedClaims.AddRange(claims);
}
public async Task IsActiveAsync(IsActiveContext context)
{
var profile = await GetUserProfile(context.Subject.GetSubjectId());
context.IsActive = (profile != null);
}
网上有多个来源展示了如何使用自定义商店进行身份验证,但它们似乎都使用 ResourceOwnerPasswordValidator。如果有人能指出这里缺少什么,那将有很大帮助。谢谢。
【问题讨论】:
-
鉴于您说它正在访问“重定向”视图,并且该视图非常简单(只是元刷新),您是否确认传入的 ReturnUrl 值是您所期望的?您可能希望使用 Fiddler 之类的工具查看网络流量,以确保实际上只发生了一个重定向。有没有可能它实际上正确地将您重定向回您的 SPA,然后以某种方式将您弹回登录页面(在重定向循环中)?
-
@BryanLewis 感谢您的回复。我确实检查了重定向,一切都设置正确。这个问题原来是下面的答案中提到的其他问题。
标签: authentication asp.net-core identityserver4