【问题标题】:Store token in httpcontext and use the same token in another request将令牌存储在 httpcontext 中并在另一个请求中使用相同的令牌
【发布时间】:2021-01-03 12:52:08
【问题描述】:

我有一个 ASP.NET Core Web 应用程序,它访问一个 Web 服务端点,然后该 Web 服务向我的应用程序发送请求。

当我点击那个 web 服务端点时,我会收到一个带有字符串值和到期时间的 web 令牌。我将它保存在 HttpContext 中以供以后使用。

当网络服务向我的应用程序发送请求时,它发送的令牌与我收到的相同。

我需要确保验证令牌与我最初在第一次请求时收到的令牌相同。

我不想将此令牌存储在我的数据库中,因为显然我必须搜索令牌列表,并且我可以使用不同的令牌,并且只要它存在于数据库中,这将起作用。

我已尝试将令牌存储在HttpContext.Items

但是,根据服务对我的应用程序的请求,令牌消失了。这些项目没有令牌,因为我怀疑它是不同的Httpcontext

在 ASP .NET Framework 上,我可以将其存储为

HttpContext.Application["WebServiceToken"] = token;

但是,我在 ASP .NET Core 上找不到这样的替代方案。

    public async Task<IActionResult> Index()
    {
        if (serviceTokenService.TokenAlreadyExists())
        {
            return ArrivalsFromDatabase();
        }

        var exampleDate = new DateTime(2016, 3, 10);
        var callback = Url.Action("ReceiveArrivalInfoFromService", "Home", null, Request.Scheme);
        bool success = false;

        var token = await this.serviceTokenService.GetServiceToken(configuration["WebServiceUrl"], exampleDate, callback);

        if (!String.IsNullOrEmpty(token.Token))
        {
            this.serviceTokenService.SavesToken(token);
            success = true;
        }
        
        if (!success)
        {
            return View("Error");
        }

        return ArrivalsFromDatabase();
    }
    public async Task<IActionResult> ReceiveArrivalInfoFromService()
    {
        var serviceToken = serviceTokenService.ReadToken();
        var isTokenValid = serviceTokenService.ValidateToken(Request, serviceToken);
        if (isTokenValid)
        {

            var arrivals = serviceTokenService.CollectArrivals(Request);
            await arrivalService.AddRangeAsync(arrivals);
        }

这是我的 Servicetoken 服务,也是我的令牌方法所在。

public class ServiceTokenService : IServiceTokenService
{
    private readonly IHttpContextAccessor httpContextAccessor;

    public ServiceTokenService(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }     

    public void SavesToken(ServiceToken token)
    {
        httpContextAccessor.HttpContext.Items["ServiceToken"] = token;
    }

    public ServiceToken ReadToken()
    {
        if (httpContextAccessor.HttpContext.Items["ServiceToken"] != null)
        {
            return httpContextAccessor.HttpContext.Items["ServiceToken"] as ServiceToken;
        }
        return null;
    }
}

在 ReadToken 上它返回 null。之前收到的令牌丢失了,因为它在 HttpContext.items 中不存在。

【问题讨论】:

  • 您使用的是什么类型的令牌?
  • 具有 Guid 字符串和到期日期的自定义项
  • 您可以始终将令牌存储为会话或 cookie,然后使用一些中间件将令牌添加到每个请求中。

标签: c# asp.net-core asp.net-web-api token httpcontext


【解决方案1】:

这是一个示例,在您的情况下使用ServiceToken 存储一个值Session 并使用Middleware 将其附加到每个请求。就我个人而言,我会使用 cookie authorization 或更好的 IMO JWT,但是为了帮助您开始与您的问题相关,这样的事情应该可以帮助您入门。

首先 - 创建中间件。
我通常喜欢创建一个文件夹Middleware,这样它在解决方案中的整洁,然后右键单击新创建的文件夹 > Add > New Item > Middleware Class 并命名你的新中间件文件。 (ServiceToken)
添加添加以下代码,这将检查会话是否有一个名为ServiceToken的键,如果有,它将ServiceToken的值添加到httpContext Request Header中。

public Task Invoke(HttpContext httpContext)
{
    // Add Token To Context If Found.
    string token = httpContext.Session.GetString("ServiceToken");
        
    // Check Something Was Found.
    if (!string.IsNullOrEmpty(token))
    {
        // Add The Custom Token Here.
        httpContext.Request.Headers.TryAdd("ServiceToken", token);
    }

    // Next.
    return _next(httpContext);
}

第二次 - 创建会话/中间件,这在Startup.cs 文件中完成。

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddDistributedMemoryCache();

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

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();
    
    // Add Session And Middleware Here.
    app.UseSession();
    app.UseServiceToken();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

第三 - 将令牌添加到服务。
在您的情况下,您将其添加到索引端点中。
这样的事情应该可以开始了。

public IActionResult Index()
{
    // Get Token.
    string fakeToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";

    // Create Sercice Not If Not Already There.
    if (!this.HttpContext.Session.TryGetValue("ServiceToken", out byte[] value))
    {
        this.HttpContext.Session.SetString("ServiceToken", fakeToken);
    }
    else
    {
        // Get The Token.
        string token = Encoding.UTF8.GetString(value);

        // TODO: Validate Here Or In The Middleware.
    }

    return View();
}

注意 - 当您从索引创建 ServiceToken 时,管道第一次完成时,将没有令牌附加到请求,因为它会在端点被调用,这意味着一旦第一个周期完成,它将被添加到请求中。

【讨论】:

  • 谢谢,但问题是 httpcontext 将有一个新实例,因为它是从 web 服务调用的...当应用程序调用服务时生成令牌。在此调用请求之后,将在我的应用程序中生成从服务到新端点的请求,并在标头中使用令牌值。我必须比较两个令牌以确保它们匹配。你的想法很好,但在我的第二个请求中,我有一个新的 httprequest 实例。
  • serviceTokenService.ReadToken(); 正在从会话中获取令牌,serviceTokenService.ValidateToken(Request, serviceToken); 正在验证令牌以及 httpcontext,此时,我想知道为什么您在令牌时还要传递 httpcontext已经通过了?另外,你是如何验证令牌的?
  • 因为token有过期时间,所以需要确认token没有过期。同样在 validate 方法中,我从请求的标头中获取 token 的值,并将其与我们正在谈论的会话进行比较,该会话具有另一个上下文实例。
  • 在我的 ReceiveArrivalinfo 方法中,我使用了您的逻辑,该逻辑具有会话中的 trygetvalue。我收到此错误:{“字符串引用未设置为字符串的实例。(参数's')”}
  • 抱歉回复晚了,s 是空对象吗?
猜你喜欢
  • 2019-05-29
  • 1970-01-01
  • 2012-02-16
  • 2016-10-25
  • 2018-04-28
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
  • 2017-01-04
相关资源
最近更新 更多