доступ к синглтону, созданному в ConfigureServices в файле startup.cs в ядре asp.net в том же методе ConfigureServices - PullRequest
0 голосов
/ 10 декабря 2018

Итак, я пытался настроить небольшой тестовый API с аутентификацией токена в форме JWT-дистрибутива, часть распространения токена работала как задумано.

Однако, поскольку я хотел создать методы для моегоСервис JWT более универсален, чтобы разрешать различные виды подписи токенов (так как я бы предпочел частную / открытую пару ключей), я попытался настроить некоторые дополнительные параметры в файлах appsettings, которые затем определяли бы способ генерации токенов,загрузка этих настроек началась с внедрения зависимостей, который я почти не исправлял до сих пор.

Итак, проблема возникла, когда я захотел взять те классы конфигурации, которые я установил, как одиночные (большинство руководств, которые япрочитайте до сих пор, что сделали это, так что я предполагаю, что это несколько правильно) и использую их в методе ConfigureServices, в который они добавили, чтобы я мог использовать параметры, которые, по моему мнению, должны были быть установлены, так как я настроил несколько строквыше, получив раздел appsettings file.

Однако, как только я пытаюсь получить к ним доступ, я ничего не получаю, и вместо этого у меня остаются пустые значения.

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        //the token config takes values from the appsettings.json file
        var tokenConf = Configuration.GetSection("TokenConfiguration");
        services.Configure<TokenConfiguration>(tokenConf);

        //the signing credentials are assigned in the JwtTokenService constructor
        var signingConf = new SigningConfiguration();
        services.AddSingleton<SigningConfiguration>(signingConf);
        //my token service
        services.AddSingleton<IJwtTokenService, JwtTokenService>();

        //i try to get hold of the actual values to use later on
        var provider = services.BuildServiceProvider();
        TokenConfiguration tc = provider.GetService<TokenConfiguration>();
        SigningConfiguration sc = provider.GetService<SigningConfiguration>();

        //i wanna use the values in here when i set the parameters for my authentication
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(x =>
        {
            x.Events = new JwtBearerEvents
            {
                OnTokenValidated = context =>
                {
                    return Task.CompletedTask;
                }
            };

            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                //values used here since i specify issuer, audience and what kind of key to use in the settings
                //the key & credentials differ based on a bool in the settings file and will either be a symmetric or asymmetric key
                ValidIssuer = tc.Issuer,
                ValidAudience = tc.Audience,
                IssuerSigningKey = sc.Key
            };
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

JwtTokenService.cs (IJwtTokenService имеет только метод CreateToken, который реализован здесь)

public class JwtTokenService : IJwtTokenService
{
    private TokenConfiguration tokenConf;
    public SigningConfiguration signingConf;

    public JwtTokenService(IOptions<TokenConfiguration> tc) {
        tokenConf = tc.Value;
        signingConf = new SigningConfiguration();

        //if the asymmetric bool is set to true, assign a new rsa keypair to the signing configuration
        //otherwise, use a symmetric key with a hmac hash
        if (tc.Value.AsymmetricKey)
        {
            using (var provider = new RSACryptoServiceProvider(2048))
            {
                signingConf.Key = new RsaSecurityKey(provider.ExportParameters(true));
            }

            signingConf.SigningCredentials =
                new SigningCredentials(
                    signingConf.Key,
                    SecurityAlgorithms.RsaSha256);
        }
        else {
            signingConf.Key = 
                new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes(tc.Value.HmacSecret));

            signingConf.SigningCredentials = 
                new SigningCredentials(
                    signingConf.Key, 
                    SecurityAlgorithms.HmacSha512);
        }
    }

    /// <summary>
    /// Creates a token based on the running configuration
    /// </summary>
    public string CreateToken(List<Claim> claims)
    {
        var token = new JwtSecurityToken(
            issuer: tokenConf.Issuer,
            audience: tokenConf.Audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(tokenConf.Minutes),
            signingCredentials: signingConf.SigningCredentials
            );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

TokenConfiguration.cs

public class TokenConfiguration
{
    public string Audience { get; set; }
    public string Issuer { get; set; }
    public int Minutes { get; set; }
    public bool AsymmetricKey { get; set; }
    public string HmacSecret { get; set; }
}

SigningConfiguration.cs

public class SigningConfiguration
{
    public SecurityKey Key { get; set; }
    public SigningCredentials SigningCredentials { get; set; }
}

appsettings.json

"TokenConfiguration": {
"Audience": "ExampleAudience",
"Issuer": "ExampleIssuer",
"Minutes": 30,
"AsymmetricKey": true,
"HmacSecret": "example-secret-top-secret-secret-is_secret"

}

(проект работает в asp.net core 2.1 в случае, если это имеет значение)

Я новичок в DI и не могу найтиВо многих примерах сценарий использования такой же, как и у меня, и в большинстве таких случаев используются реальные службы, а не добавление класса «конфигурации» через DI.

Вероятно, есть способ получше, и яЯ, вероятно, просто глуп, что не заметил или не знал, что именно нужно Google, чтобы получить правильный ответ, и, скорее всего, будет наблюдать / читать о DI после этого, независимо от этого.

Любой ввод или мысли будутвысоко ценится,поскольку я все еще плохо знаком с ядром asp.net и всем этим.

В качестве небольшого побочного вопроса относительно генерации секретного ключа, в моем случае, было бы лучше сохранить сгенерированную пару ключей вхранилище ключей, или для хранения его в памяти, или наилучшим вариантом будет генерирование их через что-то вроде openSSL и чтение из них при запуске?

1 Ответ

0 голосов
/ 10 декабря 2018

Вы запрашиваете TokenConfiguration вместо IOptions<TokenConfiguration> у ServiceProvider.Измените эти строки

   TokenConfiguration tc = provider.GetService<TokenConfiguration>();
   SigningConfiguration sc = provider.GetService<SigningConfiguration>(); 

с

    IOptions<TokenConfiguration> tc = provider.GetService<IOptions<TokenConfiguration>>();
    IOptions<SigningConfiguration> sc = provider.GetService<IOptions<SigningConfiguration>>();

А затем параметры доступа с tc.Value.

Построение ServiceProvider в ConfigureServices не очень хорошая идеяя бы взял прямо из конфига по Configuration["TokenConfiguration:Audience"] везде, где мне нужно ConfigureServices.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...