简体   繁体   English

ASP.NET Core 2.1 API JWT 令牌 Session.id 在每次请求时都会更改

[英]ASP.NET Core 2.1 API JWT token Session.id changes on every request

I have a asp.net core 2.1 API that I connect to using and Angular 4 app and authenticate thru a JWT token.我有一个 asp.net core 2.1 API,我使用它连接到 Angular 4 应用程序并通过 JWT 令牌进行身份验证。 I also have 2 SignalR hubs there as well.我也有 2 个 SignalR 集线器。

The authentication works nice and I am sure it works because after login I have access to the methods and classes I have set [Authorize] on.身份验证效果很好,我确信它可以正常工作,因为登录后我可以访问我已设置 [Authorize] 的方法和类。

The problem is the injected _accessor.HttpContext.Session.Id changes every time with every request.问题是注入的_accessor.HttpContext.Session.Id每次请求都会更改。 So the real issues is I cannot use session variables.所以真正的问题是我不能使用会话变量。

I am at a loss and it seems to me I am missing something here.我不知所措,在我看来我在这里遗漏了一些东西。 Can someone please help me with some ideas?有人可以帮我一些想法吗? Any help is much appreciated.任何帮助深表感谢。

This is my startup.cs so far:到目前为止,这是我的 startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        Configuration = configuration;
        if (env.IsDevelopment())
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.RollingFile(Path.Combine(env.ContentRootPath+"/logs/", "log-{Date}.txt"))
                //, outputTemplate: "{MachineName} {EnvironmentUserName}: {Message:lj}{NewLine}{Exception}"
                .WriteTo.Seq("http://192.168.1.164:5341")
                .Enrich.WithMachineName()
                .Enrich.WithEnvironmentUserName()
                .CreateLogger();
        }
        else
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.RollingFile(Path.Combine(env.ContentRootPath + "/logs/", "log-{Date}.txt"))
                .Enrich.WithMachineName()
                .Enrich.WithEnvironmentUserName()
                .CreateLogger();
        }
    }

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    var key = Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value);
    services.AddDbContext<PaymentServicesContext>(options => options.UseSqlServer(Configuration.GetConnectionString("PaymentDatabase")));

    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(10);
        options.Cookie.HttpOnly = true;
    });

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

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters =
        new TokenValidationParameters
        {
            LifetimeValidator = (before, expires, token, param) =>
            {
                return expires > DateTime.UtcNow;
            },
            ValidateAudience = false,
            ValidateIssuerSigningKey = true,
            ValidateIssuer = false,
            ValidateActor = false,
            ValidateLifetime = true,
            IssuerSigningKey = new SymmetricSecurityKey(key)
        };
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                var accessToken = context.Request.Query["access_token"];
                var path = context.HttpContext.Request.Path;
                if (!string.IsNullOrEmpty(accessToken))
                {
                    context.Token = accessToken;
                }
                return Task.CompletedTask;
            }
        };
    });
    services.AddAutoMapper();
    services.AddCors();
    services.AddSignalR(options => options.EnableDetailedErrors = true);

    ///services
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddTransient<IBrainzService, BrainzService>();
    services.AddTransient<ISecurityService, SecurityService>();

}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();
    loggerFactory.AddSerilog();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler(builder =>
        {
            builder.Run(async context =>
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

                var error = context.Features.Get<IExceptionHandlerFeature>();
                if (error != null)
                {
                    
                    await context.Response.WriteAsync(error.Error.Message);
                }
            });
        });
    }


    app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials())
        .UseStaticFiles()
        .UseWebSockets();

    app.UseAuthentication();
    if (!env.IsDevelopment())
    {
        app.UseHttpsRedirection();
    }
    app.UseWebSockets();

    app.UseSignalR(
        routes =>
        {
            routes.MapHub<MessagingHub>("/messagingHub");
            routes.MapHub<UpdatesHub>("/updatesHub");
        });

    app.UseSession();
    app.UseMvc();
  }
}

The configuration works.配置有效。 The problem was that Angular's HttpClient does not store/get/send cookies by default as I have found out the hard way.问题是 Angular 的 HttpClient 默认情况下不存储/获取/发送 cookie,因为我发现了困难的方法。 All I had to do was add {withCredentials: true } option to the login request and the session cookie popped into the browser!我所要做的就是向登录请求添加{withCredentials: true }选项,然后会话 cookie 就会弹出到浏览器中! To get the session back you have to add this option to all requests and the API will know the session!要恢复会话,您必须将此选项添加到所有请求,API 将知道该会话!

One solution would be to create an Interceptor to intercept all requests before it leaves the client application.一种解决方案是创建一个Interceptor以在请求离开客户端应用程序之前拦截所有请求。 This tutorial explains it well.教程解释得很好。 You can also do this on a per-request level by setting the withCredentials to true .您还可以通过将withCredentials设置为true在每个请求级别执行此操作。

const requestOptions = {
 headers: new HttpHeaders({
  'Authorization': "my-request-token"
 }),
 withCredentials: true
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM