Как вы получаете значения IOptions <T>от сервисов? - PullRequest
1 голос
/ 14 марта 2020

Я пытаюсь сделать TDD во время разработки, но я борюсь. В моем первом тесте я могу успешно получить параметры, установленные в services.AddAuthentication (...), но я не могу получить параметры из .AddCook ie (..), добавленного к предыдущему вызову. Во время отладки я вижу, что для CookieAuthenticationOptions добавлен IPostConfigureOptions, и я подозреваю, что он каким-то образом изменяет значения параметров по умолчанию, но я не знаю, как его получить.

Код для проверки:

public static void AddOpenIdConnect(this IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options => { options.MinimumSameSitePolicy = SameSiteMode.None; });

    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie(
        CookieAuthenticationDefaults.AuthenticationScheme,
        options =>
        {
            options.ExpireTimeSpan = TimeSpan.FromHours(2);
            options.SlidingExpiration = true;
            options.AccessDeniedPath = new PathString("/Error/403");
        }
    );
}

Мой первый тест проверил, что AuthenticationOptions были установлены, и он проходит:

[TestMethod]
public void AddOpenIdConnect_Should_AddAuthenticationOptions()
{
    //  arrange
    var services = new ServiceCollection();

    //  act
    services.AddOpenIdConnect();

    //  assert
    var provider = services.BuildServiceProvider();
    var authOptions = provider.GetRequiredService<IOptions<AuthenticationOptions>>();

    authOptions.Value.DefaultScheme.Should().Be(CookieAuthenticationDefaults.AuthenticationScheme);
    authOptions.Value.DefaultChallengeScheme.Should().Be(OpenIdConnectDefaults.AuthenticationScheme);
}

Этот метод завершается ошибкой, так как AccessDeniedPath возвращает настройку по умолчанию, а не настройку, которую устанавливает проверяемый код ( Вы можете видеть, что я прокомментировал проверку ExpireTimeSpan, поскольку он также не работает.)

[TestMethod]
public void AddOpenIdConnect_Should_AddCookieAuthenticationOptions()
{
    //  arrange
    var services = new ServiceCollection();

    //  act
    services.AddOpenIdConnect();

    //  assert
    var provider = services.BuildServiceProvider();
    var authCookieOptions = provider.GetRequiredService<IOptions<CookieAuthenticationOptions>>();

    //authCookieOptions.Value.ExpireTimeSpan.Should().Be(TimeSpan.FromHours(2));
    authCookieOptions.Value.SlidingExpiration.Should().BeTrue();
    authCookieOptions.Value.AccessDeniedPath.Should().Be("/Error/403");
}

Любая помощь будет принята с благодарностью, так как мне все еще нужно добавить ".AddOpenIdConnect (options =>") после этого.

Спасибо!

1 Ответ

1 голос
/ 14 марта 2020

Исходный код для расширения AddCookie показывает, что используется схема аутентификации для настройки именованного параметра при добавлении CookieAuthenticationOptions

public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, 
string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
{
    builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
    builder.Services.AddOptions<CookieAuthenticationOptions>(authenticationScheme).Validate(o => o.Cookie.Expiration == null, "Cookie.Expiration is ignored, use ExpireTimeSpan instead.");
    return builder.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
}

Исходный код

Обратите внимание на

builder.Services.AddOptions<CookieAuthenticationOptions>(authenticationScheme) //<-- Named option

Таким образом, для доступа к опции имени необходимо использовать ту же схему, которая использовалась при регистрации опции

. сделано с использованием IOptionsSnapshot<TOptions>.Get(String) метод

//...omitted for brevity

// Assert
var provider = services.BuildServiceProvider();
IOptionsSnapshot<CookieAuthenticationOptions> namedOptionsAccessor = 
    provider.GetRequiredService<IOptionsSnapshot<CookieAuthenticationOptions>>();

CookieAuthenticationOptions options = 
    namedOptionsAccessor.Get(CookieAuthenticationDefaults.AuthenticationScheme);

options.ExpireTimeSpan.Should().Be(TimeSpan.FromHours(2));
options.SlidingExpiration.Should().BeTrue();
options.AccessDeniedPath.Should().Be("/Error/403");
...