将base64URL解码为base64 -- Swift

30

我还没有找到在swift中将base64URL解码为base64格式的正确方法。

根据base64url转base64hJQWHABDBjoPHorYF5xghQ(base64URL)应该是hJQWHABDBjoPHorYF5xghQ==(base64)。这里可能存在更多差异。

stackoverflow上没有解决方案。


在右侧的“相关”部分中,有一个关于通过JavaScript进行Base64URL解码的链接。快速查看一下就可以了解它们之间的区别。 - rmaddy
3个回答

52

“base64url”与标准Base64编码有两个不同之处:

  • 在索引值为62和63的位置上使用不同的字符(-_代替了+/
  • 没有通过添加“=”字符来强制使字符串长度成为四的倍数。

(参见https://en.wikipedia.org/wiki/Base64#Variants_summary_table)。

下面是一种可能的转换函数:

func base64urlToBase64(base64url: String) -> String {
    var base64 = base64url
        .replacingOccurrences(of: "-", with: "+")
        .replacingOccurrences(of: "_", with: "/")
    if base64.characters.count % 4 != 0 {
        base64.append(String(repeating: "=", count: 4 - base64.characters.count % 4))
    }
    return base64
}

示例:

let base64url = "hJQWHABDBjoPHorYF5xghQ"
let base64 = base64urlToBase64(base64url: base64url)
print(base64) // hJQWHABDBjoPHorYF5xghQ==

if let data = Data(base64Encoded: base64) {
    print(data as NSData) // <8494161c 0043063a 0f1e8ad8 179c6085>
}

为了完整起见,这将是相反的转换:

func base64ToBase64url(base64: String) -> String {
    let base64url = base64
        .replacingOccurrences(of: "+", with: "-")
        .replacingOccurrences(of: "/", with: "_")
        .replacingOccurrences(of: "=", with: "")
    return base64url
}

Swift 4更新:

func base64urlToBase64(base64url: String) -> String {
    var base64 = base64url
        .replacingOccurrences(of: "-", with: "+")
        .replacingOccurrences(of: "_", with: "/")
    if base64.count % 4 != 0 {
        base64.append(String(repeating: "=", count: 4 - base64.count % 4))
    }
    return base64
}

Mandrill自定义跟踪域,跟踪参数p也可以用这种方式解码。提醒像我这样的人注意 :) - ergunkocak
1
我在这里为基于iOS的Passkeys(在网页上完美运行!) - lol

8
这是Martin在Swift 4扩展中发布的简化版本:
import Foundation

/// Extension for making base64 representations of `Data` safe for
/// transmitting via URL query parameters
extension Data {

    /// Instantiates data by decoding a base64url string into base64
    ///
    /// - Parameter string: A base64url encoded string
    init?(base64URLEncoded string: String) {
        self.init(base64Encoded: string.toggleBase64URLSafe(on: false))
    }

    /// Encodes the string into a base64url safe representation
    ///
    /// - Returns: A string that is base64 encoded but made safe for passing
    ///            in as a query parameter into a URL string
    func base64URLEncodedString() -> String {
        return self.base64EncodedString().toggleBase64URLSafe(on: true)
    }

}

extension String {

    /// Encodes or decodes into a base64url safe representation
    ///
    /// - Parameter on: Whether or not the string should be made safe for URL strings
    /// - Returns: if `on`, then a base64url string; if `off` then a base64 string
    func toggleBase64URLSafe(on: Bool) -> String {
        if on {
            // Make base64 string safe for passing into URL query params
            let base64url = self.replacingOccurrences(of: "/", with: "_")
                .replacingOccurrences(of: "+", with: "-")
                .replacingOccurrences(of: "=", with: "")
            return base64url
        } else {
            // Return to base64 encoding
            var base64 = self.replacingOccurrences(of: "_", with: "/")
                .replacingOccurrences(of: "-", with: "+")
            // Add any necessary padding with `=`
            if base64.count % 4 != 0 {
                base64.append(String(repeating: "=", count: 4 - base64.count % 4))
            }
            return base64
        }
    }

}

谢谢!非常方便从Swift与GMail API进行交互。 - xaphod
2
toggleBase64URLSafe是一个非常奇怪的API,特别是它的名称。为什么不将其拆分为两个单独的函数呢? - Peter Schorn

0

这是Base64URL转Base64的Objective-C版本

-(NSString *) base64urlToBase64 :(NSString *)base64url {

 NSString * base64 = [base64url stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
base64 =  [base64 stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
if(base64.length  % 4 != 0)
{
    base64 = [base64 stringByAppendingString:[self stringWithRepeatString:"=" times:(4 - base64.length % 4)]];
}
return  base64;

}

- (NSString *)stringWithRepeatString:(char *)characters times:(unsigned int)repetitions; {

unsigned long stringLength = strlen(characters);
unsigned long repeatStringLength = stringLength * repetitions + 1;
char repeatString[repeatStringLength];

for (unsigned int i = 0; i < repetitions; i++) {
    unsigned int pointerPosition = i * repetitions;
    memcpy(repeatString + pointerPosition, characters, stringLength);
}

repeatString[repeatStringLength - 1] = 0;
return  [NSString stringWithCString:repeatString encoding:NSASCIIStringEncoding];

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接