Вопрос или проблема
Я настраиваю новое приложение ASP.Net Core с использованием режима деградации OpenIdDict в качестве OAuth2 сервера. Я инициализировал сервер с помощью
builder.Services.AddOpenIddict()
.AddCore(opt => { })
.AddServer(opt =>
{
opt.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
opt.SetIssuer(new Uri("http://<my-domain>"));
opt.SetAuthorizationEndpointUris("oauth2/authorize")
.SetTokenEndpointUris("oauth2/token")
.SetIntrospectionEndpointUris("oauth2/introspect")
.SetConfigurationEndpointUris("oauth2/.well-known/openid-configuration")
.SetCryptographyEndpointUris("oauth2/.well-known/jwks");
opt.AddEphemeralEncryptionKey();
opt.AddEphemeralSigningKey();
opt.EnableDegradedMode();
opt.UseAspNetCore()
.DisableTransportSecurityRequirement();
opt.DisableAccessTokenEncryption();
opt.RequireProofKeyForCodeExchange();
// не используется в режиме деградации
opt.UseReferenceAccessTokens()
.UseReferenceRefreshTokens();
opt.AddEventHandler<OpenIddictServerEvents.ProcessAuthenticationContext>(x =>
{
x.UseInlineHandler(c =>
{
return default;
});
});
opt.AddEventHandler<OpenIddictServerEvents.ValidateAuthorizationRequestContext>(x =>
{
// проверить клиента, например, client_id, redirect_url
x.UseScopedHandler<ValidateAuthorizationRequestContext>();
});
opt.AddEventHandler<OpenIddictServerEvents.HandleAuthorizationRequestContext>(x =>
{
x.UseScopedHandler<HandleAuthorizationRequestContext>();
});
opt.AddEventHandler<OpenIddictServerEvents.ValidateIntrospectionRequestContext>(x =>
{
x.UseInlineHandler(c =>
{
return default;
});
});
public class ValidateAuthorizationRequestContext : IOpenIddictServerHandler<OpenIddictServerEvents.ValidateAuthorizationRequestContext>
{
public ValueTask HandleAsync(OpenIddictServerEvents.ValidateAuthorizationRequestContext context)
{
if (!String.Equals(context.ClientId, "test", StringComparison.Ordinal))
{
context.Reject(
error: Errors.InvalidClient,
description: "Указанный 'client_id' не соответствует зарегистрированному приложению."
);
}
return default;
}
}
public class HandleAuthorizationRequestContext : IOpenIddictServerHandler<OpenIddictServerEvents.HandleAuthorizationRequestContext>
{
public ValueTask HandleAsync(OpenIddictServerEvents.HandleAuthorizationRequestContext context)
{
// работать с ClaimsPrincipal
var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType);
var claim = new Claim(Claims.Subject, "testSubject");
claim.SetDestinations(Destinations.AccessToken);
identity.AddClaim(claim);
//context.Principal = new ClaimsPrincipal(identity);
context.SignIn(new ClaimsPrincipal(identity));
return default;
}
}
Я обнаружил, что при использовании клиента OAuth2 для входа, обратные вызовы для ProcessAuthenticationContext
(я не знаю, для чего предназначен этот обратный вызов), ValidateAuthorizationRequestContext
(проверить, действителен ли client_id) и HandleAuthorizationRequestContext
(установить sub
и другие утверждения в токене) будут вызываться последовательно. Но ни в одном из этих трех обратных вызовов я не вижу возможностей для отображения страницы входа, чтобы пользователь мог ввести свое имя пользователя и пароль. Каковы лучшие практики для этого?
Ответ или решение
Вопрос о том, как реализовать страницу входа в систему в OpenIdDict в режиме деградации, действительно важен для обеспечения безопасности и удобства пользователей. Давайте рассмотрим, как это сделать шаг за шагом.
Введение
OpenIdDict — это мощная библиотека для ASP.NET Core, позволяющая реализовать сервер авторизации OAuth2 и OpenID Connect. При использовании режима деградации, важным аспектом является реализация процесса аутентификации пользователей, включая отображение страницы входа, на которой пользователи могут вводить свои учетные данные.
Понимание потоков
При настройке OpenIdDict, вы определяете различные обработчики событий для управления процессом авторизации. Однако, такие обработчики, как ProcessAuthenticationContext
, ValidateAuthorizationRequestContext
и HandleAuthorizationRequestContext
, в основном предназначены для работы с клиентами и кодами доступа, а не для взаимодействия с конечным пользователем.
Реализация страницы входа
-
Создание контроллера для обработки входа:
Для отрисовки страницы входа вам нужно создать отдельный контроллер (например,AccountController
), который будет отвечать за отображение формы аутентификации и обработку введенных данных.public class AccountController : Controller { [HttpGet] public IActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } [HttpPost] public async Task<IActionResult> Login(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { // Верификация пользователя (например, через сервис аутентификации) var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, isPersistent: false, lockoutOnFailure: false); if (result.Succeeded) { // Перенаправление на возвращаемый URL верно по логике приложения return LocalRedirect(returnUrl); } ModelState.AddModelError(string.Empty, "Неверный логин или пароль."); } return View(model); } }
-
Intégrирование в процесс авторизации:
Чтобы модифицировать процесс аутентификации и направить пользователя на страницу входа, вы можете изменить обработчикValidateAuthorizationRequestContext
, для того чтобы, в случае, если пользователь не аутентифицирован, перенаправить его на вашу страницу входа:opt.AddEventHandler<OpenIddictServerEvents.ValidateAuthorizationRequestContext>(x => { x.UseScopedHandler<ValidateAuthorizationRequestContext>(); // Добавьте здесь свою логику перенаправления if (!context.IsAuthenticated) { // Запоминаем URL для перенаправления после успешной аутентификации context.SetParameter("return_url", context.RedirectUri); context.Response.RedirectUri = Url.Action("Login", "Account", new { returnUrl }); context.Success(); } });
-
Создание представления для формы входа:
Вам нужно создать представление, которое будет отображать форму для ввода имени пользователя и пароля. Например:@model LoginViewModel <form asp-action="Login" method="post"> <h2>Вход</h2> <div asp-validation-summary="All" class="text-danger"></div> <div class="form-group"> <label asp-for="Username"></label> <input asp-for="Username" class="form-control" /> <span asp-validation-for="Username" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" class="form-control" /> <span asp-validation-for="Password" class="text-danger"></span> </div> <input type="hidden" name="returnUrl" value="@ViewBag.ReturnUrl" /> <button type="submit" class="btn btn-primary">Войти</button> </form>
Заключение
Внедряя страницу входа в OktaDict в режиме деградации, вы обеспечиваете защиту и удобство для пользователей, что является важным аспектом любого веб-приложения. Следуя указанным шагам, вы создаете интуитивно понятный интерфейс, точно реагируя на входящие запросы на авторизацию. Помните о необходимости соблюдать все требования безопасности к паролям и учетным данным, а также использовать HTTPS для обеспечения безопасной передачи данных.
Надеюсь, это руководство будет полезным при разработке вашего приложения на ASP.NET Core с использованием OpenIdDict. Если у вас есть дополнительные вопросы, не стесняйтесь их задавать.