【问题标题】:.net core 5.0 CurrentPrincipal resets value.net core 5.0 CurrentPrincipal 重置值
【发布时间】:2021-04-22 10:30:33
【问题描述】:

我有一个 .net core 5.0 应用程序,它需要额外的证书验证,并且基于证书我在 db 中获得了某些角色。我将这些作为声明存储在 Thread.CurrentPrincipal 或 HttpContext.User 中。但是当调用到达 Controller 时,它们都会恢复它们的默认值。

这是 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)
    {
        services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
        {
            options.RevocationMode = X509RevocationMode.NoCheck;
            options.AllowedCertificateTypes = CertificateTypes.All;
            options.Events = new CertificateAuthenticationEvents
            { //container.Resolve<CertificateHandler>();
                OnCertificateValidated = context =>
                {
                    if (!ValidateCertificate(context.ClientCertificate))
                    {
                        CreateErrorResponse(context, StatusCodes.Status403Forbidden, MaloConstants.NoValidClientCertificateReceived);
                        return Task.CompletedTask;
                    }

                    var certRoles = certificateProcessor.GetRoleIDs(context.ClientCertificate)
                    var roleClaims = certRoles.Roles.Distinct().OrderBy(r => r)
                        .Select(s => new Claim(ClaimsHelper.MALoInternalRole, s.ToString(CultureInfo.InvariantCulture), typeof(int).Name)).ToList();
                    var id = new ClaimsIdentity(roleClaims, AuthenticationType.X509.ToString());

                    var principal = new ClaimsPrincipal(new[] { id });

                    Thread.CurrentPrincipal = principal;
                    context.HttpContext.User = principal;
                    context.Success();
                    return Task.CompletedTask;
                }
            };
        });

        services.AddCertificateForwarding(options =>
        {
            options.CertificateHeader = "X-SSL-CERT";
            options.HeaderConverter = (headerValue) =>
            {
                X509Certificate2 clientCertificate = null;

                if (!string.IsNullOrWhiteSpace(headerValue))
                {
                    byte[] bytes = StringToByteArray(headerValue);
                    clientCertificate = new X509Certificate2(bytes);
                }

                return clientCertificate;
            };
        });

        services.AddControllers().AddNewtonsoftJson(o => o.SerializerSettings.ContractResolver = new DefaultContractResolver());
    }
    ....
    private static byte[] StringToByteArray(string hex)
    {
        int NumberChars = hex.Length;
        byte[] bytes = new byte[NumberChars / 2];

        for (int i = 0; i < NumberChars; i += 2)
        {
            bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        }

        return bytes;
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        var logger = new NLogger();
        logger.Info("Application Configure started");
        
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseCertificateForwarding();
        app.UseAuthentication();

        app.UseAuthorization();
        app.UseMiddleware<ContentNegociationHandler>();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

        logger.Info("Application Configure completed");
    }
}

这是 Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, logging) =>
            {
                logging.ClearProviders();
                logging.SetMinimumLevel(LogLevel.Trace);
            })
            .UseNLog()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
                webBuilder.ConfigureKestrel(options =>
                {
                    options.ConfigureHttpsDefaults(o =>
                        o.ClientCertificateMode =
                            ClientCertificateMode.RequireCertificate);
                });
            });
}

是否有理由不存储声明?有解决办法吗?

编辑:设置Thread.CurrentPrincipal 的图像 Before。控制器中Thread.CurrentPrincipal 值的图像 After

【问题讨论】:

  • 你在哪里写回数据库?
  • @jdweng 我不知道。我只从数据库中读取。我获得了当前证书的角色,并希望将这些角色作为声明存储在 CurrentPrincipal 中。
  • 您正在写入不是 CurrentPrincipal 的 Thread.CurrentPrincipal。
  • 我把 CurrentPrincipal 写成一个通用术语,因为我尝试同时使用 Thread.CurrentPrincipal 和 context.HttpContext.User 来存储它,但是当调用到达控制器时它们都会被重置。
  • 控制器解析接收响应。在控制器中解析响应后,您必须更改值。

标签: c# .net-core current-principal


【解决方案1】:

找到答案: 您可以像这样设置新身份:

context.Principal = principal;

然后我可以使用以下方法在控制器中检索新主体:

ControllerContext.HttpContext.User;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 2021-03-24
    • 2016-02-21
    • 2021-10-30
    • 1970-01-01
    • 2021-05-03
    • 2021-06-01
    相关资源
    最近更新 更多