【问题标题】:returnUrl drops second querystring parameterreturnUrl 删除第二个查询字符串参数
【发布时间】:2021-09-01 09:12:57
【问题描述】:

我正在使用 MVC 5。问题是 SSO 在身份验证后重定向回应用程序后,登录方法 returnUrl 删除了 applicaitonId 查询字符串参数。请帮忙!

这是流程。

  1. 应用将未经授权的用户重定向到登录方法,并在 returnUrl 中保留原始请求。

    原来的请求是

     http://localhost:25451/shared/download?documentGroup=133&applicationId=3153
    

    returnUrl 是

     /shared/download?documentGroup=133&applicationId=3153
    
  2. 应用重定向到 SSO CAS 服务器,将 HttpUtility.Encode returnUrl 作为参数与登录 URL 一起作为服务参数的一部分发送。

     https://{redacted}/cas/login?service=http://localhost:25451/account/login%3freturnUrl%3d%2fshared%2fdownload%3fdocumentGroup%3d133%26applicationId%3d3153
    
  3. 身份验证后,CAS 服务器附加授权票证并重定向回服务 URL。这就是提琴手所展示的。

     http://localhost:25451/account/login?returnUrl=/shared/download?documentGroup=133&applicationId=3153&ticket={redacted}
    
  4. 这就是问题所在。 login方法中的returnuRL很简单

    /shared/download?documentGroup=133.  
    

    returnUrl 不再有 applicationId。

有趣的是,这条线工作得很好。

var ticket = Request.QueryString.Get("ticket");

我尝试对整个 serviceUrl 进行编码并尝试仅对 returnUrl 进行编码(见下文),但我遇到了同样的缺少 ApplicationId 问题。

[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
    var ticket = Request.QueryString.Get("ticket");

    if (!string.IsNullOrEmpty(ticket))
    {
        //verify the ticket...
        return RedirectToLocal(returnUrl);
    }

    var serviceUrl = Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host + (Request.Url.IsDefaultPort ? "" : ":" + Request.Url.Port) + "/account/login" + "?returnUrl=" + HttpUtility.UrlEncode(returnUrl);
    var authenCasUrl = string.Format("{0}login?service={1}", "https://{redacted}/", serviceUrl);
    return Redirect(authenCasUrl);
}

【问题讨论】:

  • 如果你反转两个参数 documentGroup=133&applicationId=3153 => applicationId=3153&documentGroup=133 总是第一个参数持久化?
  • 感谢@B.Lec 的回复。切换变量会删除 documentId。因此,无论顺序如何,似乎都删除了第二个参数。
  • 我对正在发生的事情一无所知,作为一种解决方法,您应该尝试仅使用 1 个“状态”参数并将您需要的所有值序列化为 base64 编码的 json
  • 看看stackoverflow.com/questions/372865/path-combine-for-urls Flurl 支持 url.combine 处理所有 url 组合魔法。

标签: asp.net asp.net-mvc


【解决方案1】:

我没有使用 asp 或 SSO 的经验,但您可能需要 HttpUtility.UrlEncode serviceUrl 变量的值?

var authenCasUrl = string.Format("{0}login?service={1}", "https://{redacted}/", HttpUtility.UrlEncode(serviceUrl));

由于服务参数被CAS解码一次,然后returnUrl的值被你的服务器解码。

var returnUrl = "/shared/download?documentGroup=133&applicationId=3153";
var serviceUrl = "http://localhost:25451/account/login?returnUrl=" + HttpUtility.UrlEncode(returnUrl);
var casUrl = "https://{redacted}/cas/login?service=" + HttpUtility.UrlEncode(serviceUrl);

这给出了:

serviceUrl = http://localhost:25451/account/login?returnUrl=%2Fshared%2Fdownload%3FdocumentGroup%3D133%26applicationId%3D3153
casUrl     = https://{redacted}/cas/login?service=http%3A%2F%2Flocalhost%3A25451%2Faccount%2Flogin%3FreturnUrl%3D%252Fshared%252Fdownload%253FdocumentGroup%253D133%2526applicationId%253D3153

解释尝试:
  • 您向 CAS 服务器发出 HTTP 请求。它的实现拆分查询参数并解码每个值(可能还有键)。其中之一是服务参数,现在(解码后)是一个有效的 URL。
  • CAS 服务器使用来自服务参数(到您的服务器)的 URL 发出 HTTP 请求,并附加票证。
  • 您拆分查询参数并解码每个值(可能还有键)。

如果您只对returnUrl 编码一次,您的serviceUrl 将与您在第三点中显示的一样:

http://localhost:25451/account/login?returnUrl=/shared/download?documentGroup=133&applicationId=3153&ticket={redacted}

分割查询字符串的算法如何区分serviceUrl 中的?&returnUrl 中的那些? 它怎么知道ticket不属于returnUrl

正如您在上面的代码中看到的,您没有对returnUrl 进行两次编码。
您将一个 URL 放入另一个 URL 的参数中,然后将该 URL 放入第三个 URL 的参数中。

当您组合查询时,您需要为每个值(可能还有键)调用UrlEncode。该值是 URL、JSON 还是任意用户输入都没有关系。

【讨论】:

  • 这项工作,我将奖励赏金。在我接受它作为答案之前,我想知道它为什么有效?对 returnUrl 进行双重编码没有意义。
  • 你能把你的代码从 HttpUtility.Encode 改成 HttpUtility.UrlEncode 吗?谢谢!
  • @salli 我已按要求添加了解释,并将Encode 更改为UrlEncode。我希望这是可以理解的。
【解决方案2】:

由于您的 URL 将实际调用此站点,因此我认为他们不会丢弃其中的一部分。 让我们在这里尝试一下,因为我在结合 asp.NET 的 url 字符串中遇到了类似的参数问题。

首先,让我们从您的请求中获取未经编辑的 URL:

string UneditedUrl = Request.RawUrl;

因为我们在 ? 之前不需要任何东西mark,我们稍微缩短一下:

string QueryString = (UneditedUrl.IndexOf('?') < UneditedUrl.Length - 1) ? UneditedUrl.Substring(UneditedUrl.IndexOf('?') + 1) : String.Empty;

这一行还包括没有 ?标记或参数,如果是,将返回一个空字符串。只是为了好的衡量,我们不希望这里有任何例外。您可以在此处检查QueryString 是否包含您输入的两个或多个参数。

如果此处不完整,则不是您的代码有问题。在你做之前,你的 URL 上已经有一些东西了,可能是你的主机。也许检查你的 IIS 的设置。


如果您的参数在编辑后的QueryString 中正确无误,您可以按照以下步骤继续获取它们:

我了解到有一种方法可以让您的框架完成将参数解析为名称/值集合的工作。所以让我们试一试吧:

NameValueCollection ParaCollection = HttpUtility.ParseQueryString(QueryString);

您现在可以使用ParaCollection[0]ParaCollection["documentGroup"] 之类的索引来检查参数及其值。

编辑: 我发现了使我得出使用Request.RawUrl 的结论的问题。由于这可能不是答案,因此了解Request.RawUrl 是用户调用的实际 URL 而不是服务器执行的 URL 可能会有所帮助:RawURL vs URL

【讨论】:

  • 这是一个很好的替代解决方案。但是,@dmtweigt 提供的解决方案会返回 applicationId。
  • @salli 有意思,QueryString 中的 applicationId 是不是已经不见了?
猜你喜欢
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 2020-11-13
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多