【问题标题】:Returning response header OnAuthenticationFailed返回响应头 OnAuthenticationFailed
【发布时间】:2019-09-18 09:54:11
【问题描述】:

如果用户发送的令牌已过期,我将尝试返回更改后的标头,以便在过期时重新发送我的刷新令牌。

我正在使用带有“进程内”托管的 .NET Core 2.2,以防万一。

这是我的ConfigureServices 方法,来自我的Startup.cs

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = "bearer";
    options.DefaultChallengeScheme = "bearer";
}).AddJwtBearer("bearer", options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateAudience = false,
        ValidateIssuer = false,
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["serverSigningPassword"])),
        ValidateLifetime = true,
        ClockSkew = System.TimeSpan.Zero //the default for this setting is 5 minutes
    };
    options.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents
    {
        OnAuthenticationFailed = context =>
        {
            if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
            {
                context.Response.Headers.Add("Token-Expired", "true");
            }
            return System.Threading.Tasks.Task.CompletedTask;
        }
    };
});

然后,当我尝试使用以下内容从 javascript 获取“授权”端点时。

async function fetchWithCredentials(url, options) {    
    options.headers['Authorization'] = 'Bearer ' + jwtToken;
    var response = await fetch(url, options);
    if (response.ok) { //all is good, return the response
        return response;
    }

    console.log(response.headers) //nothing in this array

    // it will never do this "if" statement because there are no headers
    if (response.status === 401 && response.headers.has('Token-Expired')) {
        // refresh the token
        return await fetchWithCredentials(url, options); //repeat the original request
    } else { //status is not 401 and/or there's no Token-Expired header
        return response; 
    }
}

这张图片来自于将鼠标悬停在标题上。它确实达到了我的断点(对于context.Response.Headers.Add(),我可以看到计数 = 1(当我检查它时,它是“令牌过期”)。

最后,这是 Postman 在请求失败后的屏幕截图,因此响应正在发送,但在我的 JS 中没有收到。

关于为什么我的标头不符合我在 javascript 中的响应的任何想法?

【问题讨论】:

    标签: javascript c# api asp.net-core http-headers


    【解决方案1】:

    当您在 CORS 上使用 Fetch API 时,访问响应标头会受到限制。由于此限制,您只能访问以下标准标头:

    • Cache-Control
    • Content-Language
    • Content-Type
    • Expires
    • Last-Modified
    • Pragma

    参考:https://stackoverflow.com/a/44816592/5751404

    因此,在客户端访问自定义标头的一种方法是将标头 access-control-expose-headers 添加到响应中,并使用逗号分隔的标头:

    services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
    {
        builder.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader()
              .WithExposedHeaders("Token-Expired"); ;
    }));
    

    Configure:

    app.UseCors("MyPolicy");
    

    这样您就可以使用 Fetch API over CORS 从客户端访问自定义标头。

    【讨论】:

    • 嗨@NanYu,我只希望在身份验证失败时返回该响应。不是每个请求
    • @thalacker ,您只是在OnAuthenticationFailed 事件中添加Token-Expired作为标头值,以满足您的要求。
    【解决方案2】:

    我在这里描述两者 - 1. 令牌过期并获取刷新令牌 2. 仅适用于未经授权的请求。

    async function fetchWithCredentials(url, options) {    
        options.headers['Authorization'] = 'Bearer ' + jwtToken;
        var response = await fetch(url, options);//this is a function for get a response. I didn't explain it here. Hope you understand. 
        if (response.ok) {
            return response;
        }
    
        let flag:boolean=false; //set flag for executing one if statement at a time.
    
    if (response.status == 401 && response.headers.has('Token-Expired')) {
            // refresh the token
            flag=true;  //set flag true.
            //write something as per your requirement.
        } 
    
    if (response.status == 401 && flag==false) {
            **// Only for unauthorized request. You can use this for your problem.**
            //write something as per your requirement.
        } 
    }
    

    最重要的是,您必须在 startup.cs 中使用以下代码。

    services.AddCors(context => context.AddPolicy("CustomPolicy", builder =>
    {
        builder.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader()
              .WithExposedHeaders("Token-Expired"); ;
    }));
    
    

    在配置中:

    app.UseCors("CustomPolicy");
    

    并按原样使用下面的代码。

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = "bearer";
        options.DefaultChallengeScheme = "bearer";
    }).AddJwtBearer("bearer", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false,
            ValidateIssuer = false,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["serverSigningPassword"])),
            ValidateLifetime = true,
            ClockSkew = System.TimeSpan.Zero //the default for this setting is 5 minutes
        };
        options.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents
        {
            OnAuthenticationFailed = context =>
            {
                if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                {
                    context.Response.Headers.Add("Token-Expired", "true");
                }
                return System.Threading.Tasks.Task.CompletedTask;
            }
        };
    });
    

    现在,您将在客户端收到响应。 希望你能找到你的解决方案。如有任何疑问,请告诉我。

    【讨论】:

      猜你喜欢
      • 2018-07-16
      • 1970-01-01
      • 2011-02-16
      • 2020-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-27
      相关资源
      最近更新 更多