【问题标题】:How to encode/decode product id in path in ASP.NET如何在 ASP.NET 的路径中编码/解码产品 ID
【发布时间】:2017-09-28 17:33:27
【问题描述】:

ASP.NET/Mono MVC4 购物车应用程序用户产品代码作为 awstats 分析的 url 名称,例如:

http://myshop.com/Store/Details/PRODUCT1

使用默认路由和控制器

    public class StoreController : MyApp.ControllerBase
    {

        public ActionResult Details(string id)
        {
  ....

PRODUCT1 是产品代码。 如果产品代码在目录名称中包含 / 和其他不允许的字符,Web 服务器会抛出错误。

产品代码应该是人类可读的,因为分析会显示网址。 如何编码产品代码以作为目录名称传递并在控制器中解码? 编码后产品代码应保持唯一。

在 ASP.NET 中是否有一些内置函数或一些实现此功能的源代码?

使用jquery、jquery ui、razor 视图引擎。

更新

我尝试通过创建 Razor 助手在评论中推荐

@helper Details(string toode)
{
    @Url.Action("Details", new { id = HttpUtility.UrlEncode(toode) });
}

然后使用

<a href="@Details(someproduct)">

这会导致错误:

检测到来自客户端 (%) 的潜在危险 Request.Path 值。 GET /Store/Details/S%c3%9c%c3%9cTAJA HTTP/1.0

% chareter 不允许出现在 url 路径中。 所以不能使用 UrlEncode。如何编码/解码?

【问题讨论】:

  • 您可以使用 url 编码/解码 (HttpUtility.UrlEncode),但编码后的 url 看起来有点难看。我宁愿产品代码不包含这些有问题的字符,因此人类和服务器都可读。
  • 用户喜欢1/23:3/3+3/?A之类的产品代码。目前在 Razor 视图中使用 @Url.Action("Details", new { product = "1/23:3/3+3/?A" })),但 awstats 分析将所有产品页面视为单个页面。我应该像@("~/Store/Details/"+HttpUtility.UrlEncode("1/23:3/3+3/?A")) 那样手动创建网址还是有更好的方法?或者可以配置 awstats 或其他基于服务器的免费分析吗?
  • 1/23:3/3+3/?A urlencoded 是1%2F23%3A3%2F3%2B3%2F%3FA。我不确定有人会喜欢它。但这是我的主观意见,如果您认为不是,请不要关注它。无论如何,如果你真的坚持使用这些尴尬的 url,urlencoding 听起来是唯一的解决方案。
  • % 字符不允许在 url 路径中。所以不能使用 UrlEncode。我更新了问题。如何编码/解码?
  • 这是因为您的助手可能是错误的。我相信Url.Action 已经做了一些编码。试试"/Store/Details?id="+HttpUtility.UrlEncode(toode)

标签: asp.net asp.net-mvc asp.net-mvc-4 razor urlencode


【解决方案1】:

您可以像这样使用加密和解密算法(密码学)来实现您的目标......

 public class CryptoEngine
    {

        private static CryptoEngine _instance;
        private CryptoEngine() { }
        public static CryptoEngine Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new CryptoEngine();

                return _instance;
            }
        }

        static readonly string PasswordHash = "@dM!nCo$";
        static readonly string SaltKey = "AdMinCos";
        static readonly string VIKey = "Polar!s@dM!nCoN$";

        public string Encrypt(string plainText)
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
            var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));

            byte[] cipherTextBytes;

            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();
                    cipherTextBytes = memoryStream.ToArray();
                    cryptoStream.Close();
                }
                memoryStream.Close();
            }
            return Convert.ToBase64String(cipherTextBytes);
        }

        public string Decrypt(string encryptedText)
        {
            encryptedText = encryptedText.Trim();
            if (encryptedText.Contains(" "))
            {
                encryptedText = encryptedText.Replace(" ", "+");
            }

            byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };

            var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
            var memoryStream = new MemoryStream(cipherTextBytes);
            var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
        }
    }

并像这样使用它......

"/Store/Details?id="+CryptoEngine.Instance.Encrypt(toode))

在您的操作中,您可以像这样解密它...

public ActionResult Details(string id)
{
   string _id = CryptoEngine.Instance.Decrypt(id);
   .......

您可以设置您的 PasswordHash、SaltKey 和 VIKey 我想这就是你想要的。

您可以查看有关密码学的更多信息 Reference

【讨论】:

  • 这使得 url 无法被人类阅读。 url 应该是可读的,因此它们并用于 awstats analtyicts 以跟踪查看次数最多的产品。如何使网址可读?
  • 代码将只加密 ID 而不是整个 url,因此 url 不会被加密和人类可读,但你的 id 将在最后加密。
  • 我需要产品 id 也是可读的。通常它包含常规字符,只有少数特殊字符。 ID 部分也应该是用户友好的
猜你喜欢
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 2013-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多