#authentication #openid-connect #blazor-server-side
Вопрос:
У меня было серверное приложение .NET 5 Blazor, работающее с аутентификацией у поставщика сервера идентификации 4. Приложение размещено в кластере Kubernetes, управляемом входным контроллером Nginx.
Исходное приложение содержало следующий код в Startup.cs
...
services
.AddAuthentication(opt => {
opt.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opt.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect("oidc", opt => {
opt.Authority = Configuration["oidc:Authority"];
opt.ClientId = Configuration["oidc:ClientId"];
opt.ClientSecret = Configuration["oidc:ClientSecret"];
opt.Scope.Add("openid");
opt.Scope.Add("profile");
opt.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" };
opt.ResponseType = "code id_token"; // id_token is needed for Hybrid Grant Type
opt.SaveTokens = true;
opt.GetClaimsFromUserInfoEndpoint = true;
opt.Events = new OpenIdConnectEvents {
OnAccessDenied = context => {
context.HandleResponse();
context.Response.Redirect("/");
return Task.CompletedTask;
}
};
});
...
// Required to use HTTPS for redirect_uri during authentication -- https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-5.0
var forwardedHeaderOptions = new ForwardedHeadersOptions() {
ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
};
app.UseForwardedHeaders(forwardedHeaderOptions);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
В LoginDisplay.razor
файле была настроена «обычная» (как видно из некоторых «старых» статей) настройка
...
<NotAuthorized>
<a class="ml-3" href="login?redirectUri=/">Log in</a>
</NotAuthorized>
с Login.cshtml.cs
файлом, содержащим
public class LoginModel :
PageModel {
public async Task OnGet(string redirectUri) {
await HttpContext.ChallengeAsync("oidc", new AuthenticationProperties() { RedirectUri = redirectUri });
}
}
Я решил обновить приложение до .NET 6 (мы пытаемся решить несвязанную проблему с модулем k8s, который постоянно перезапускается каждые несколько минут без видимой причины), одновременно «очищая» код. На мой взгляд, кажется бессистемным и грязным использовать компонент razor «вход», который просто вызывает файл «login.cshtml».
Другая причина изменения заключается в том, что мы хотим, чтобы все представления автоматически перенаправляли пользователя на аутентификацию. Другими словами, пользователю не нужно нажимать на ссылку «Войти».
Новый код очень, очень похож в том, что Program.cs
файл содержит следующее (в .NET 6 файлы Startup.cs и Program.cs были объединены)
builder.Services
.AddAuthentication(options => {
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// Have tried setting other Scheme properties
//options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// Have tried **both** OpenIdConnectDefaults.AuthenticationScheme and "oidc"
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
//options.DefaultChallengeScheme = "oidc";
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
//.AddOpenIdConnect("oidc", options => {
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => {
// Have try both with and without setting these options
//options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//options.SignOutScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.Authority = ssoSettings.Authority;
options.ClientId = ssoSettings.ClientId;
options.ClientSecret = ssoSettings.ClientSecret;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.ResponseType = "code id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.TokenValidationParameters = new() {
NameClaimType = "name"
};
options.Events = new OpenIdConnectEvents {
OnAccessDenied = context => {
context.HandleResponse();
context.Response.Redirect("/");
return Task.CompletedTask;
}
};
});
Большая разница заключается в том, что мы используем FallbackPolicy
их для принудительной авторизации всех вызовов
builder.Services.AddAuthorization(options => {
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
});
В результате получается , что всякий раз, когда Сервер идентификации перенаправляет обратно /signin-oidc
, эта конечная точка возвращает другую 302
, отправляющую пользователя обратно на сервер идентификации и, следовательно, вызывающую цикл.
Однако это происходит только тогда, когда приложение развертывается в нашем кластере Kubernetes. Я не могу добиться, чтобы это происходило локально при отладке в Visual Studio. В VS все работает, как и ожидалось.
Я также заметил, что в журналах K8s есть следующие записи
{"EventId":1,"LogLevel":"Warning","Category":"Microsoft.AspNetCore.Http.ResponseCookies","Message":"The cookie u0027.AspNetCore.OpenIdConnect.Nonce.CfDJ8HJzxP7cycdIvDHSkH_UahcueTVoI4VJZuIcSNHCrfknCfeAbVENZr7-FTCN9iXO1k1D4Q3QPjkzuwFIrfdAhHBkQe48lPbdssB4uN7_9_ueE5AhkSlG6-MUqIaXTtfar4ZZD7h65wjyAKuTuHhkfdNIAhDB170xb-gAd8CzOApVuaY9JMhcU_w-kt_kvIx04mQPmPxNr-uU9NUEhxyME1ZPrRkqSg2gLgnlyJEfTheyU85o2R4z-IhqhYcFb80wvIu6okozDqqpA29kLQ434RUu0027 has set u0027SameSite=Noneu0027 and must also set u0027Secureu0027.","State":{"Message":"The cookie u0027.AspNetCore.OpenIdConnect.Nonce.CfDJ8HJzxP7cycdIvDHSkH_UahcueTVoI4VJZuIcSNHCrfknCfeAbVENZr7-FTCN9iXO1k1D4Q3QPjkzuwFIrfdAhHBkQe48lPbdssB4uN7_9_ueE5AhkSlG6-MUqIaXTtfar4ZZD7h65wjyAKuTuHhkfdNIAhDB170xb-gAd8CzOApVuaY9JMhcU_w-kt_kvIx04mQPmPxNr-uU9NUEhxyME1ZPrRkqSg2gLgnlyJEfTheyU85o2R4z-IhqhYcFb80wvIu6okozDqqpA29kLQ434RUu0027 has set u0027SameSite=Noneu0027 and must also set u0027Secureu0027.","name":".AspNetCore.OpenIdConnect.Nonce.CfDJ8HJzxP7cycdIvDHSkH_UahcueTVoI4VJZuIcSNHCrfknCfeAbVENZr7-FTCN9iXO1k1D4Q3QPjkzuwFIrfdAhHBkQe48lPbdssB4uN7_9_ueE5AhkSlG6-MUqIaXTtfar4ZZD7h65wjyAKuTuHhkfdNIAhDB170xb-gAd8CzOApVuaY9JMhcU_w-kt_kvIx04mQPmPxNr-uU9NUEhxyME1ZPrRkqSg2gLgnlyJEfTheyU85o2R4z-IhqhYcFb80wvIu6okozDqqpA29kLQ434RU","{OriginalFormat}":"The cookie u0027{name}u0027 has set u0027SameSite=Noneu0027 and must also set u0027Secureu0027."}}
{"EventId":1,"LogLevel":"Warning","Category":"Microsoft.AspNetCore.Http.ResponseCookies","Message":"The cookie u0027.AspNetCore.Correlation.pvnQ3UKTs2JF6O6CTBUG3cUuoLtj7_Gm16zOzgsWFVMu0027 has set u0027SameSite=Noneu0027 and must also set u0027Secureu0027.","State":{"Message":"The cookie u0027.AspNetCore.Correlation.pvnQ3UKTs2JF6O6CTBUG3cUuoLtj7_Gm16zOzgsWFVMu0027 has set u0027SameSite=Noneu0027 and must also set u0027Secureu0027.","name":".AspNetCore.Correlation.pvnQ3UKTs2JF6O6CTBUG3cUuoLtj7_Gm16zOzgsWFVM","{OriginalFormat}":"The cookie u0027{name}u0027 has set u0027SameSite=Noneu0027 and must also set u0027Secureu0027."}}
Хотя я понимаю , что мне следует обновить свой сервер идентификации, чтобы установить secure
, этот же сервер уже работал с предыдущей версией приложения. И это все еще работает (и я нигде не вижу этого предупреждения), когда я запускаю приложение локально, поэтому я не уверен, связано ли это предупреждение с циклом перенаправления.
Одна из моих проблем-поиск недавних статей/примеров на сервере Blazor и проверка подлинности, которая не связана с Azure AD или ASP.NET Идентификационные данные (локальные учетные записи). Слишком много ссылок связано с Blazor WASM. Даже веб-сайт Identity Server 4 с его примерами по-прежнему ограничен MVC. Есть ли какие-либо текущие примеры, с которыми кто-то сталкивался?
Комментарии:
1. Когда вы работаете локально, вы обычно работаете по протоколу HTTPS (против локального хоста), но в облаке службы обычно работают по протоколу HTTP за каким-либо прокси-сервером. Это распространенная причина неприятностей.