安全的方式传递参数从视图到控制器,并返回它作为一个视图

本文关键字:视图 一个 返回 方式传 参数 安全 控制器 | 更新日期: 2023-09-27 18:10:38

我正在寻找querystring的安全替代方案,其中我将传递一个参数到同一控制器上的控制器方法并将其作为视图返回。

类别视图:

@foreach (Project.Framework.ModelClasses.productCategories productCategories in ViewBag.Categories)
    {           
        @Html.ActionLink(productCategories.description, "Products", "Shop", new { id = "", categoryID = productCategories.categoryID, description = productCategories.description }, null)
    }

控制器方法:

public ActionResult Products(string categoryID, string keyword, string description)
    {
        ViewBag.appPath = ConfigurationManager.AppSettings["appPath"].ToString();
        Methods Methods = new Methods();
        Methods.tokenHeader = (string)Session["token"];
        Methods.cookieContainer = (CookieContainer)Session["cookies"];
        Response shopnowProductsResponse = Methods.shopnowProductsGet(categoryID, keyword);
        if (shopnowProductsResponse.Code == "000")
        {
            List<product> products = new List<product>();
            products = (List<product>)shopnowProductsResponse.Data;
            string FPRFlag = "0";
            foreach (product product in products)
            {
                if (FPRFlag != "1")
                {
                    if (product.FPRFlag == "1")
                    {
                        FPRFlag = product.FPRFlag;
                    }
                }
                else
                {
                    goto nextState;
                }
            }
        nextState:
            ViewBag.FPRFlag = FPRFlag;
            ViewBag.Description = description;
            ViewBag.Products = products;
        }
        return View();
    }

注意:关键字可选

安全的方式传递参数从视图到控制器,并返回它作为一个视图

假设您只是想以一种最终用户无法从url中抓取所有产品数据列表的方式对这些链接进行编码,那么您可以通过在链接中使用替代代码来实现这一点。我将使用哈希值:

@foreach (Project.Framework.ModelClasses.productCategories category in ViewBag.Categories)
{
    @Html.ActionLink(category.description, "Products", "Shop", 
        new { 
            hc = category.categoryID.GetHashCode() 
        })
}

然后在控制器上查找哈希码而不是categoryID

仍然有两个问题:

  1. 哈希码将在浏览器的地址栏中可见。
  2. 哈希码列表每次都是相同的。

第一个可以通过中间操作来修复,该操作将哈希码转换回categoryID并将结果存储在Session存储中,然后重定向到Products页面:

public ActionResult SetCategory(int hc)
{
    string catID = HashToCategoryID(hc);
    Session["categoryID"] = catID;
    return RedirectToAction("Products");
}

这不仅将用户的浏览器放回到Products页面,而且还确保(在大多数情况下)SetCategory URL甚至不会出现在浏览器历史记录中。一般来说,浏览器历史记录甚至不会显示它从Products页面导航出来,所以点击Back按钮会把它们从页面带回到它们第一次进入页面之前的位置。

另一个问题-哈希码不变-可以通过几种方式解决:用一个每次访问都会改变的值(如会话ID)来添加哈希值,或者生成随机值并将其存储在Session存储中以供查找。

例如:

// after loading your products:
// something to salt the hash codes with:
string salt = (DateTime.Now - DateTime.Today).TotalMilliseconds.ToString();
// generate hash codes for all the product categories
var hashcodes = products.Select(p => new { h = (salt + p.categoryID).HashCode(), c = p.categoryID });
// create hash->categoryID dictionary and save in Session
var hashtocat = hashcodes.ToDictionary(hc => hc.h, hc => hc.c);
Session["HashToCategory"] = hashtocat;
// create categoryID->hash dictionary and save in ViewBag
var cattohash = hashcodes.ToDictionary(hc => hc.c, hc => hc.h);
ViewBag["CategoryToHash"] = cattohash; 

现在,每次加载页面时,您将获得一组不同的哈希值。生成的链接变成:

@{ // grab hashcode dictionary from ViewBag
    Dictionary<string, int> hashcodes = ViewBag["CategoryToHash"] as Dictionary<string, int>;
}
@foreach (Project.Framework.ModelClasses.productCategories category in ViewBag.Categories)
{
    @Html.ActionLink(product.description, "SetCategory", new { hc = hashcodes[product.categoryID] })
}

实际上,你现在有一个单次使用的代码列表,过期,并被替换为新的每次用户重新访问Products页面。让相同的代码在同一类别中多次工作的几率是微乎其微的,除非从同一会话中单击链接,否则它将失败。

说到失败……你需要在里面添加一些错误处理