C# JWTBeareAuthentication未设置HttpContext用户

C# JWTBeareAuthentication未设置HttpContext用户,c#,asp.net-core,authentication,bearer-token,jwt-auth,C#,Asp.net Core,Authentication,Bearer Token,Jwt Auth,我很难在.NetCore Web API中找到关于这个主题的相关信息:JWTBeareAuthentication。令牌是由IdentityServer发布并通过前端客户端应用程序发送的OIDC id令牌。令牌被正确地接收和验证,从而产生一个具有15个声明的经过身份验证的ClaimsPrincipal,但当请求到达应用程序时,该主体在HttpContext中不存在。存在未经身份验证的匿名用户,而不是验证令牌时出现的用户 这个api是由它的作者(不是我)构思出来使用OIDC cookie身份验证的

我很难在.NetCore Web API中找到关于这个主题的相关信息:JWTBeareAuthentication。令牌是由IdentityServer发布并通过前端客户端应用程序发送的OIDC id令牌。令牌被正确地接收和验证,从而产生一个具有15个声明的经过身份验证的ClaimsPrincipal,但当请求到达应用程序时,该主体在HttpContext中不存在。存在未经身份验证的匿名用户,而不是验证令牌时出现的用户

这个api是由它的作者(不是我)构思出来使用OIDC cookie身份验证的,但我正在尝试将它转换为使用JWT承载身份验证

据我所知,根据我能找到的所有例子,我做的每件事都是正确的,我没有想法。感谢您的帮助

我已经在下面发布了完整的Startup.cs文件,很抱歉所有的代码,但是你应该能够看到所有相关的东西

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Autofac;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Autofac.Configuration;
using Autofac.Extensions.DependencyInjection;
using CAS.Authorization.Api.Configuration;
using CAS.Authorization.Api.Defaults.Configuration;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Swashbuckle.AspNetCore.Swagger;

namespace CAS.Authorization.Api
{
    [ExcludeFromCodeCoverage]
    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 IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddAuthentication(options =>
                {
                    //options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    //options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                   // options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                //.AddCookie()
                .AddJwtBearer(options =>
                {
                    options.Authority = "http://localhost:40800";
                    options.RequireHttpsMetadata = false;
                    options.SaveToken = true;
                    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        ValidateIssuer = false,
                        ValidIssuer = "http://localhost:40800",
                        ValidateAudience = false,
                        ValidAudience = "http://localhost:22426"
                    };
                    options.Events = new JwtBearerEvents()
                    {
                        OnTokenValidated = async context =>
                        {
                            //This does not work, however the context.Principal IS authenticated
                            //and DOES have claims (15 of them).
                            context.HttpContext.User = context.Principal;
                        }
                    };
                });
            //.AddOpenIdConnect(options =>
            //{
            //    options.SignInScheme = "Cookies";
            //    options.Authority = "http://localhost:40800";
            //    options.ClientId = "defaultClientId";
            //    options.SignInScheme = "Cookies";
            //    options.RequireHttpsMetadata = false;
            //    options.ResponseType = "code";
            //    options.Scope.Add("profile");
            //    options.GetClaimsFromUserInfoEndpoint = true;
            //    options.SaveTokens = true;
            //    options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");
            //});

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

            services.AddHttpContextAccessor();
            services.AddAuthorization(PolicyConfiguration.SetupPolicies);

            services.AddSingleton<IAuthorizationHandler, AccessPolicyHandler>();
            services.AddTransient<IActionContextAccessor, ActionContextAccessor>();

            //Api Versioning
            //services.AddApiVersioning(o =>
            //{
            //    o.ReportApiVersions = true;
            //    o.ApiVersionReader = new UrlSegmentApiVersionReader();
            //});

            services.Configure<BusSettings>(Configuration.GetSection("BusSettings"));

            //Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Title = "CAS Authorization API", Version = "v1" });
                
                //Locate the XML file being generated by ASP.NET...
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.XML";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);

                //... and tell Swagger to use those XML comments.
                c.IncludeXmlComments(xmlPath);
            });

            // Add Autofac
            // ConfigurationModule accepts JSON configuration for other modules/components to register,
            // instead of having references here to those modules, directly.
            // If we ever want to remove those direct references, this should still work.
            // config.AddJsonFile comes from Microsoft.Extensions.Configuration.Json
            var config = new ConfigurationBuilder();
            config.AddJsonFile("modules.json");

            // Register the ConfigurationModule with Autofac.
            var module = new ConfigurationModule(config.Build());
            var builder = new ContainerBuilder();
            builder.RegisterAssemblyModules();
            builder.RegisterModule(module);
            builder.Populate(services);

            var container = builder.Build();
            return new AutofacServiceProvider(container);
        }

        // 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.UseCookiePolicy();
            app.UseAuthentication();

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

            //Swagger UI
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "CAS Authorization API - v1");
                c.RoutePrefix = string.Empty;
            });
        }
    }
}

问题解决了。这是一个概念验证,Identity Server、客户端应用程序和API都在Visual Studio调试中运行,并具有尽可能多的默认设置。我用http访问API。当我点击它的https端口时,它工作了。显然,身份验证中间件仅在请求使用https时设置用户。

请显示您尝试访问用户对象的位置谢谢,我编辑了这篇文章,添加了一个尝试访问用户的示例。检查这两个链接,我认为您不必在启动类中设置用户,.Net core应该这样做,但是必须从具有Authorize属性的控制器调用UserIdentityService,这可能会有所帮助,感谢您查看并分享这些示例。我知道不必在启动时设置用户,但这样做确实允许我打断它,并查看context.Principal是否具有正确的值。这表明令牌已被接收和验证,并且所有预期的声明都已存在。但当稍后访问时,该主体不是HttpContext中的主体。Authorize属性在涉及的控制器上,这没有区别。
    public class UserIdentityService : IUserIdentityService
    {
        private HttpContext _context;

        public UserIdentityService(IHttpContextAccessor contextAccessor)
        {
            _context = contextAccessor?.HttpContext ?? throw new ArgumentNullException();
        }

        public string UserName => _context.User.FindFirst(ClaimTypes.Name)?.Value;

        public Guid Sub => Guid.Parse(_context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value);

        public Claim[] GetPermissionClaims(string permissionName, string resourceName)
        {
            if (string.IsNullOrWhiteSpace(permissionName)) throw new ArgumentException("Invalid permission name");

            if (string.IsNullOrWhiteSpace(resourceName)) throw new ArgumentException("Invalid resource name");

            return _context.User?.Claims?.Where(c => c.Type.Contains("ORG:") && c.Value == resourceName.ToUpper() + permissionName.ToUpper()).ToArray();
        }

        public Claim[] GetClaimsByOrganization(string orgName)
        {
            if (string.IsNullOrWhiteSpace(orgName)) throw new ArgumentException("Invalid organization name");

            return _context.User?.Claims?.Where(c => c.Type == "ORG:" + orgName.ToUpper()).ToArray();
        }
    }