【问题标题】:Pass request context during RedirectToAction c#在 RedirectToAction c# 期间传递请求上下文
【发布时间】:2021-09-15 23:11:33
【问题描述】:

我正在使用基本 API 控制器的 RedirectToAction 方法。第一个控制器需要修改请求标头(我似乎可以这样做),但不会保留更改。

这是我正在尝试做的简化实现。

   [HttpGet]
        public IActionResult Get(string str)
    {
      // The request comes with a request header with key "Authorization" and value "ABC"

     HttpContext.Request.Headers.Remove("Authorization");
     HttpContext.Request.Headers.Add("Authorization", "XYZ");
        return RedirectToAction("B");
    }

    [HttpGet]
    public IActionResult B()
    {

        var value = HttpContext.Request.Headers.First(x => x.Key == "Authorization");   // I want this to be ""XYZ" , but it remains "ABC"
        return Ok();
    }

关于如何让第二个操作使用我在第一个操作中更新的请求标头的任何想法。

编辑:

我们所有的控制器/操作都使用核心中间件 JWT Auth Policy 进行身份验证 只有操作一允许匿名访问。 使用“代码”(用于创建 JWT 令牌)的内部相关解决方案调用操作一。 所有其他操作都需要 JWT 进行身份验证。

“代码”和 JWT Token 有独立的过期时间,也持有一些数据。

“代码”中的信息被认为是最新的。可以使用“代码”和 JWT 令牌调用操作一。

重定向是我清除旧 JWT 令牌的方式。

当使用有效的“代码”调用操作一时,会创建一个新的 JWT。然后我想重定向到一个将验证 JWT 令牌的控制器(使用中间件)。

我知道我可以手动执行此操作,但尝试触发核心中间件。

【问题讨论】:

  • 你需要它改变响应头......不是请求头......
  • 这不是我需要的。 Action B的response需要返回,但是第一个Action需要根据请求来的内容做一些修改。
  • 这是不可能的。 HTTP 是一种无状态协议,因此,每个请求都是独立的。重定向只是返回带有 Location 标头的 301、302 或 307。而已。请求-响应周期完成。由客户端决定,然后向 Location 标头中的 URL 发出新请求,而 Web 浏览器恰好会自动执行该请求。但是,这是一个全新的请求,它不知道也不关心是否发生了重定向,甚至不知道以前曾与此服务器进行过通信。

标签: c# asp.net-core


【解决方案1】:

RedirectToAction 向浏览器返回一个302 响应,它告诉浏览器开始对新 URL 的新请求。所以你在B() 中的代码在浏览器发起一个全新的请求后被命中。因此,您在B() 中查看的Request 对象与您在Get() 中修改的对象完全不同。

这显然不是你想要做的。无需重定向,只需返回 B():

[HttpGet]
public IActionResult Get(string str)
{
    // The request comes with a request header with key "Authorization" and value "ABC"

    HttpContext.Request.Headers.Remove("Authorization");
    HttpContext.Request.Headers.Add("Authorization", "XYZ");
    return B();
}

但是重写请求标头确实有些不对劲。这有点像改写历史。另一种方式是使用HttpContext.Items来存储一个值:

[HttpGet]
public IActionResult Get(string str)
{
    HttpContext.Items["Authorization"] = "XYZ";
    return B();
}

[HttpGet]
public IActionResult B()
{
    var value = HttpContext.Items["Authorization"] as string ?? HttpContext.Request.Headers.First(x => x.Key == "Authorization");
    return Ok();
}

HttpContext.Items 中的值在单个请求的生命周期内都存在。

如果您必须重定向,那么您可以使用TempData 来保存数据,直到它在下一个请求中被读取:

[HttpGet]
public IActionResult Get(string str)
{
    TempData["Authorization"] = "XYZ";
    return RedirectToAction("B");
}

[HttpGet]
public IActionResult B()
{
    if (TempData.Contains("Authorization")) {
        HttpContext.Request.Headers.Remove("Authorization");
        HttpContext.Request.Headers.Add("Authorization", TempData["Authorization"]);
    }
    var value = HttpContext.Request.Headers.First(x => x.Key == "Authorization");
    return Ok();
}

【讨论】:

  • 两个建议都很好,我几乎认为我已经破解了它,但两者都有问题。如果我不使用重定向,则操作方法不会像控制器操作那样执行(即,它是经过身份验证的方法,但没有重定向操作,无需身份验证即可访问)
  • 至于第二个选项,头部需要在请求中,因为我使用核心中间件来验证 JWT 令牌,核心在授权头部中查找。
  • 我在答案中添加了另一个选项,您可以在其中跨请求为用户存储数据。看起来还是不太理想。我觉得有更好的方法来做你想做的事情 - 但我不知道你为什么要这样做,所以我不能说。
  • 我会更新问题。我不想让问题变得太复杂,但我的要求似乎变得复杂了。
  • 您仍然可以使用TempData 方法,但您需要在授权中间件触发之前将其移到管道的更上方(就像在授权之前添加的另一个自定义中间件一样)。如何在中间件中访问TempData,请参见here
猜你喜欢
  • 2018-03-25
  • 1970-01-01
  • 2017-02-18
  • 1970-01-01
  • 2023-04-03
  • 2016-09-16
  • 2018-10-22
  • 1970-01-01
  • 2013-03-28
相关资源
最近更新 更多