AddOpenIdConnect() и политика по умолчанию в качестве политики возврата вызывают цикл входа в систему-oidc

#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 за каким-либо прокси-сервером. Это распространенная причина неприятностей.