【问题标题】:Generating URL-friendly unique string with embedded datetime生成带有嵌入日期时间的 URL 友好的唯一字符串
【发布时间】:2011-06-17 08:42:12
【问题描述】:

我个人厌倦了为我的 Web 项目重新实现“票证”机制以进行一些一次性操作,例如帐户激活或密码重置。我知道这很简单,但它需要我保留(并坚持!)两条数据:票证本身和到期日期。

所以我有这个想法,生成一个唯一的字符串,其中嵌入了日期时间(到期日期),我们可以在作为 url-request 的一部分接收时检查它。

我从这个开始:

var clearTicket = Convert.ToInt64(expiration.ToString("yyyyMMddhhmm")).ToString("x12") + key.ToString("N");

但我希望它更紧凑。我想是BaseXX-ish。 任何想法如何有效地实现这种编码/解码(考虑 url-safe charset)?

【问题讨论】:

  • 看起来不是很安全......更改到期日期很容易
  • 确实会,但不会以任何方式影响安全性。该字符串将存储在数据库中,实际上我将通过它搜索用户配置文件,然后才提取日期时间以查看令牌是否已过期。

标签: c#


【解决方案1】:

我花了一些时间,所以我希望它有所帮助:

首先,您应该从“yyyyMMddhhmm”中减去 200000000000,因为在接下来的 88 年中,您实际上不需要前两位数。

这是 Base64 编码和解码的实现,仅使用 URL 安全字符。
如果您有任何问题,请随时提出。

public string Base64Encode (Int64 Number)
{
    string HelpString = "";
    if (Number >= 64)
    {
        HelpString = Base64Encode(Number / 64);
    }
    return (HelpString += Base64EncodeHelper(Number % 64));
}

public string Base64EncodeHelper(Int64 Number)
{
    string HelpString = "";
    Number += 65;
    if ((Number >= 65 && Number <= 90) || (Number >= 97 && Number <= 122))  // 0 - 25 and 32 - 57
    {
        HelpString = Convert.ToString((char)Number);
    }
    else if (Number >= 91 && Number <= 96)                                  // 26 - 31
    {
        HelpString = Convert.ToString((char)(Number - 43));
    }
    else if (Number >= 123 && Number <= 126)                                // 58 - 61
    {
        HelpString = Convert.ToString((char)(Number - 69));
    }
    else if (Number == 127)                                                 // 62
    {
        HelpString = "-";
    }
    else                                                                    // 63
    {
        HelpString = "_";
    }
    return (HelpString);
}

public Int64 Base64Decode(string Encoded)
{
    Int64 Result = 0, HelpInt = 0;
    int i = Encoded.Length - 1;
    foreach (char Character in Encoded)
    {
        int CharInInt = (int)Character;
        if (Character == '_')
        {
            HelpInt = 63;
        }
        else if (Character == '-')
        {
            HelpInt = 62;
        }
        else if (((CharInInt + 69) >= 123) && ((CharInInt + 69) <= 126))
        {
            HelpInt = CharInInt + 4;
        }
            else if (((CharInInt + 43) >= 91) && ((CharInInt + 43) <= 96))
        {
            HelpInt = CharInInt - 22;
        }
        else
        {
             HelpInt = CharInInt - 65;
        }
        Result += Convert.ToInt64((Math.Pow(64, Convert.ToDouble(i))) * HelpInt);
        i--;
    }
    return Result;
}

【讨论】:

  • 谢谢,有趣的方法!您对年份的前几位是正确的,不需要它们。我现在无法检查,但既然你已经实现了自己的 base64,我相信它是 url 安全的?我已经设法使用日期和 guid 的整个十六进制字符串(大约 224 位)创建了该想法的工作实现,但由于规则而无法在此处发布。我会在星期一这样做。但我对我的 base64 转换并不完全满意,所以我会试试你的方法。
  • 好吧,编码后的字符串由小写字母 [a,z]、大写字母 [A,Z]、数字 [0,9]、“破折号”[-] 和下划线 [_] 组成。所有这些都可以在 URL 中使用。
【解决方案2】:

你可以像这样扩展字符串:

public static string ToURLParameter(this string text)
{
    if (String.IsNullOrEmpty(text)) return "";

    // to lowercase, trim extra spaces
    text = text.Trim();

    var len = text.Length;
    var sb = new StringBuilder(len);
    bool prevdash = false;
    char c;

    //
    text = text.Replace('Å', 'A');
    text = text.Replace('å', 'a');
    text = text.Replace('Ä', 'A');
    text = text.Replace('ä', 'a');
    text = text.Replace('Ö', 'O');
    text = text.Replace('ö', 'o');

    for (int i = 0; i < text.Length; i++)
    {
        c = text[i];
        if (c == ' ' || c == ',' || c == '.' || c == '/' || c == '\\' || c == '-')
        {
            if (!prevdash)
            {
                sb.Append('-');
                prevdash = true;
            }
        }
        else if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'))
        {
            sb.Append(c);
            prevdash = false;
        }
        if (i == 80) break;
    }

    text = sb.ToString();
    // remove trailing dash, if there is one
    if (text.EndsWith("-"))
        text = text.Substring(0, text.Length - 1);

    return text;
}

然后你可以在任何字符串变量上使用它:

string something = "asdfljasdklf";

<%= something.ToUrlParameter() %>

【讨论】:

  • 如果您使用 asp.net mvc,您可以使用带有约束的 url 路由来获取 url 中的值。
  • Lasse Edsvik - 但是当我稍后将其作为参数接收时,我必须对其进行解码。此外,我不能确定它是否会在 ToUrlParameter() 转换后保持唯一。
【解决方案3】:

我终于使用这些答案中描述的技术创建了一个解决方案:

Compressing big number (or string) to small value

How do you convert Byte Array to Hexadecimal String, and vice versa?

效果很好!

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    相关资源
    最近更新 更多