#asp.net-core #asp.net-identity #blazor #identityserver4
Вопрос:
Так что у меня есть Asp.Net Основной веб-проект Mvc IdentityServer, другой веб-проект для управления IdentityServer(администратор) и проект веб-api IdentityServer.
Все они находятся в одном и том же решении Visual studio.
Как сервер идентификации, так и проекты Api имеют свои собственные классы Startup.cs, в которых я регистрирую личность следующим образом
services.AddIdentity<EntityUser, EntityRole>()
.AddRoles<EntityRole>()
.AddEntityFrameworkStores<IdentityServerDbContext>()
.AddDefaultTokenProviders();
Проект администратора регистрирует HttpClient в своей программе.cs для связи с веб-api
builder.Services.AddHttpClient("IdentityServerApi",
client => client.BaseAddress = new Uri(_BASEADDRESS))
.AddHttpMessageHandler(sp =>
{
var handler = sp.GetService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: new[] { ApplicationConsts.ApiBaseUrl },
scopes: new[] { ApplicationConsts.ApiName });
return handler;
});
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("IdentityServerApi"));
То, что я пытаюсь сделать, — это заставить пользователя сбросить свой пароль при входе в систему.
Поэтому для достижения этой цели в действии контроллера учетной записи/входа в систему проекта IdentityServer я создаю токен и перенаправляю пользователя на страницу сброса пароля в проекте администратора:
if (isForcePasswordResetRequired)
{
if (hasUserDoneForcePasswordReset)
{
return await SignInTheUser(model, user, context);
}
else
{
var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
if (result.Succeeded)
{
// show him password reset form
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
token = HttpUtility.UrlEncode(token);
var callbackUrl = ApplicationConsts.AdminBaseUrl $"/Account/ResetPassword?userId={user.Id}amp;token={token}";
return Redirect(callbackUrl);
}
}
}
else
{
return await SignInTheUser(model, user, context);
}
Как только пользователь перенаправлен на страницу сброса пароля (которая находится в проекте администратора), ему предлагается ввести новый пароль и подтвердить новый пароль. При отправке вызывается следующая функция для пересылки информации на уровень Api:
public async Task SavePassword()
{
ResetPasswordDto resetPasswordDto = new ResetPasswordDto();
resetPasswordDto.UserId = userId_par;
resetPasswordDto.Token = HttpUtility.UrlEncode(token_par);
resetPasswordDto.Password = userPasswordDto.Password;
HttpResponseMessage httpResponse;
var url = $"{ApplicationConsts.ApiBaseDnsUrl}/Account/user/resetpassword";
httpResponse = await HttpClientService.AnonymousHttpClient.PostAsJsonAsync<ResetPasswordDto>(url, resetPasswordDto);
if (httpResponse.IsSuccessStatusCode)
{
toastService.ShowSuccess("Password changed successfully. Please log in using your new password.");
NavManager.NavigateTo("AdminBaseUrl");
}
else
{
toastService.ShowError("Something went wrong.");
}
}
оттуда вызывается действие Api, которое вызывает метод репозитория для сброса пароля, как показано ниже:
public virtual async Task<IdentityResult> UserResetPassword(string userId, string token, string newPassword)
{
token = HttpUtility.UrlDecode(token);
var user = await userManager.FindByIdAsync(userId);
var res = await userManager.ResetPasswordAsync(user, token, newPassword);
if (res.Succeeded)
{
return res;
}
else throw new Exception(string.Join(",", res.Errors.Select(x=> x.Code)));
}
Проблема, с которой я сталкиваюсь, заключается в том, что токен не проверяется, даже если токен, сгенерированный в IdentityServer, идентичен тому, который передается выше в метод ResetPasswordAsync. Штамп безопасности не является нулевым.
Я предполагаю, что это как-то связано с тем фактом, что токен был сгенерирован в проекте IdentityServer, который использует свой собственный экземпляр UserManager, а затем я пытаюсь проверить его через проект Api, у которого снова есть собственный экземпляр UserManager.
Если это так, как я могу использовать экземпляр UserManager в разных проектах, в данном случае в проектах IdentityServer и Api?
Комментарии:
1. Нет, ты не можешь так поступать, и ты не должен так поступать. Вы должны защитить свои конечные точки API с помощью аутентификации по токену Jwt; то есть вы должны передать токен Jwt, выданный сервером идентификации, в HTTP-вызовах конечным точкам. Эта процедура может быть прозрачной и автоматической в зависимости от выбранного вами шаблона проекта VS. В противном случае вам потребуется вручную добавить токен jwt в заголовок авторизации вашей службы HttpClient.
2. Прежде чем продолжить свой проект с помощью IdentityServer, убедитесь, что вы прочитали эту статью ( devblogs.microsoft.com/aspnet/… ) корпорацией Майкрософт и сопровождающими ее комментариями. Лично я покончил с сервером идентификации.