【问题标题】:How to achieve Base64 URL safe encoding in C#?如何在 C# 中实现 Base64 URL 安全编码?
【发布时间】:2014-12-08 19:52:09
【问题描述】:

我想在 C# 中实现 Base64 URL 安全编码。在 Java 中,我们有一个通用的 Codec 库,它为我提供了一个 URL 安全编码字符串。如何使用 C# 实现相同的目标?

byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes("StringToEncode");
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);

上面的代码将其转换为 Base64,但它填充了==。有没有办法实现 URL 安全编码?

【问题讨论】:

  • 你不能在BASE64中的字符串上使用Url.Encode吗?
  • c#中哪个命名空间Url类存在?
  • 看一下:msdn.microsoft.com/en-us/library/…你需要引用System.Web组件。
  • 它正在将 = 转换为 %3D。我不想要那个。
  • 那么url safe 是什么意思? %3D 是网址安全的。

标签: c# encoding base64


【解决方案1】:

在 url 中使用 简单地交换字母 是很常见的,因此不需要 % 编码; 65 个字符中只有 3 个有问题 - +/=。最常见的替换是- 代替+_ 代替/。至于填充:删除它=);您可以推断所需的填充量。在另一端:只需反转过程:

string returnValue = System.Convert.ToBase64String(toEncodeAsBytes)
        .TrimEnd(padding).Replace('+', '-').Replace('/', '_');

与:

static readonly char[] padding = { '=' };

并反转:

string incoming = returnValue
    .Replace('_', '/').Replace('-', '+');
switch(returnValue.Length % 4) {
    case 2: incoming += "=="; break;
    case 3: incoming += "="; break;
}
byte[] bytes = Convert.FromBase64String(incoming);
string originalText = Encoding.ASCII.GetString(bytes);

然而,有趣的问题是:这与“通用编解码器库”使用的方法相同吗?首先要进行测试肯定是合理的——这是一种非常常见的方法。

【讨论】:

  • 在通用编解码器中,他们使用 [0-9a-zA-Z_-] 字符作为 url 安全模式。
  • 这在 wiki page for Base64 的 URL applications 下也有提及。 en.wikipedia.org/wiki/Base64
  • 你也有这个功能 'stackoverflow.com/questions/1886686/…' 为你做所有的辛苦工作。
  • 为什么我们不需要:案例1:传入+=“===”;休息; ?
  • @alexdafranca 因为它永远不会有 1 的长度 mod 4。3x8 位变成 4x6 位(每 6 位是所选字母表中 64 个字符之一),0x8 位被编码为 0x6 位没有填充,1x8 位被编码为带有== 填充的 2x6 位,2x8 被编码为带有= 填充的 3x6,3x8 被编码为没有填充的 4x6,然后它被对齐以便重复。没有任何东西被编码为 1x6 位,因此您永远不需要 === 填充。
【解决方案2】:

您可以使用命名空间 Microsoft.IdentityModel.Tokens 中的类 Base64UrlEncoder

const string StringToEncode = "He=llo+Wo/rld";

var encodedStr = Base64UrlEncoder.Encode(StringToEncode);
var decodedStr = Base64UrlEncoder.Decode(encodedStr);

if (decodedStr == StringToEncode)
    Console.WriteLine("It works!");
else
    Console.WriteLine("Dangit!");

【讨论】:

  • 这比公认的答案要干净得多。有什么缺点吗?
  • 请注意:Microsoft.IdentityModel.Tokens 是一个必须下载的 NuGet 包。
  • 我假设这不是跨平台的。是这样吗?
【解决方案3】:

如果您使用的是 ASP.NET Core,另一种选择是使用 Microsoft.AspNetCore.WebUtilities.WebEncoders.Base64UrlEncode

如果您未使用 ASP.NET Core,the WebEncoders source 可在 Apache 2.0 License 下使用。

【讨论】:

    【解决方案4】:

    根据此处的答案以及一些性能改进,我们发布了一个非常易于使用的url-safe base64 implementation to NuGet,其源代码为available on GitHub(MIT 许可)。

    使用很简单

    var bytes = Encoding.UTF8.GetBytes("Foo");
    var encoded = UrlBase64.Encode(bytes);
    var decoded = UrlBase64.Decode(encoded);
    

    【讨论】:

    【解决方案5】:

    要根据 RFC4648 获得 URL 安全的类似 base64 的编码,但不是“base64url”,请使用 System.Web.HttpServerUtility.UrlTokenEncode(bytes) 进行编码,并且 System.Web.HttpServerUtility.UrlTokenDecode(bytes) 解码。

    【讨论】:

    • 这不提供符合 RFC4648 标准的 URL 安全 Base64 编码。另见this Q&A谨慎使用。
    【解决方案6】:

    最简单的解决方案: (没有填充)

    private static string Base64UrlEncode(string input) {
        var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
        // Special "url-safe" base64 encode.
        return Convert.ToBase64String(inputBytes)
          .Replace('+', '-') // replace URL unsafe characters with safe ones
          .Replace('/', '_') // replace URL unsafe characters with safe ones
          .Replace("=", ""); // no padding
      }
    

    归功于:Tholle

    【讨论】:

      【解决方案7】:
          public string Decode(string str)
          {
             byte[] decbuff = Convert.FromBase64String(str.Replace(",", "=").Replace("-", "+").Replace("/", "_"));
             return System.Text.Encoding.UTF8.GetString(decbuff);
          }
          
          public string Encode(string input)
          {
              byte[] encbuff = Encoding.UTF8.GetBytes(input ?? "");
              return Convert.ToBase64String(encbuff).Replace("=", ",").Replace("+", "-").Replace("_", "/");
          }
      

      这是与 JavaScript 保持一致的方法!

      【讨论】:

        【解决方案8】:

        这是另一种解码 url-safe base64 的方法,它与 Marc 以相同的方式编码。我只是不明白为什么4-length%4 有效(确实如此)。

        如下,只有origin的位长是6和8的公倍数,base64不加“=”到结果。

        1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8 
        1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6
                        "=="            "="
        

        所以我们可以反过来做,如果结果的位长不能被8整除,它已经被追加了:

        base64String = base64String.Replace("-", "+").Replace("_", "/");
        var base64 = Encoding.ASCII.GetBytes(base64String);
        var padding = base64.Length * 3 % 4;//(base64.Length*6 % 8)/2
        if (padding != 0)
        {
            base64String = base64String.PadRight(base64String.Length + padding, '=');
        }
        return Convert.FromBase64String(base64String);
        

        【讨论】:

          【解决方案9】:

          在 UWP 中使用 Microsoft 加密引擎。

          uint length = 32;
          
          IBuffer buffer = CryptographicBuffer.GenerateRandom(length);
          string base64Str = CryptographicBuffer.EncodeToBase64String(buffer)
                             // ensure url safe
                             .TrimEnd('=').Replace('+', '-').Replace('/', '_');
          
          return base64Str;
          

          【讨论】:

            【解决方案10】:

            Karanvir Kang 的回答很好,我投了赞成票。但是,它确实在字符串的末尾留下了一个奇数字符(表示删除的填充字符的数量)。这是我的解决方案。

            var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
            var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
            var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
            

            【讨论】:

              猜你喜欢
              • 2021-12-04
              • 1970-01-01
              • 2012-06-21
              • 2016-08-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多