Декодируйте base64URL в base64-Swift

Я не нашел правильного способа декодировать base64URL в формат base64 в swift.

по данным помощью base64url в base64 hJQWHABDBjoPHorYF5xghQ(помощью base64url) должна быть hJQWHABDBjoPHorYF5xghQ==(в base64). Здесь может быть больше различий.

в stackoverflow нет решений.

2 ответов


"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
}

вот очищенная версия того, что Мартин опубликовал в расширении 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
        }
    }

}