在 Swift 中解码 JSON Web 令牌

Posted

技术标签:

【中文标题】在 Swift 中解码 JSON Web 令牌【英文标题】:Decoding JSON Web Tokens in Swift 【发布时间】:2015-05-23 01:06:48 【问题描述】:

尝试在 Swift 中解码 JWT 有效负载并且遇到了非常困难的时间

static func decodePayload(tokenstr: String) 

    //splitting JWT to extract payload
    let arr = split(tokenstr) $0 == "."

    //base64 encoded string i want to decode
    let base64String = arr[1] as String
    println(base64String) //eyJleHAiOjE0MjY4MjIxNjMsImlkIjoiNTUwYjA3NzM4ODk1NjAwZTk5MDAwMDAxIn0

    //attempting to convert base64 string to nsdata 
    let nsdata: NSData = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))

    //decoding fails because nsdata unwraps as nil
    let base64Decoded: NSString = NSString(data: nsdata!, encoding: NSUTF8StringEncoding)!



【问题讨论】:

【参考方案1】:
eyJleHAiOjE0MjY4MjIxNjMsImlkIjoiNTUwYjA3NzM4ODk1NjAwZTk5MDAwMDAxIn0

不是有效的 Base64 编码字符串,因为它的长度 不是 4 的倍数。一些 Base64 解码器可以容忍这个错误,但是 NSData 方法没有。

所以这实际上是服务器端创建的错误 Base64 编码的字符串。如有必要,您可以在您的应用程序中修复它 通过使用 = 字符添加所需的填充(针对 Swift 2 更新的代码):

var base64String = arr[1] as String
if base64String.characters.count % 4 != 0 
    let padlen = 4 - base64String.characters.count % 4
    base64String += String(count: padlen, repeatedValue: Character("="))

现在解码按预期工作:

if let data = NSData(base64EncodedString: base64String, options: []),
    let str = String(data: data, encoding: NSUTF8StringEncoding) 
    print(str) // "exp":1426822163,"id":"550b07738895600e99000001"


斯威夫特 4:

var base64String = "eyJleHAiOjE0MjY4MjIxNjMsImlkIjoiNTUwYjA3NzM4ODk1NjAwZTk5MDAwMDAxIn0"

if base64String.count % 4 != 0 
    let padlen = 4 - base64String.count % 4
    base64String.append(contentsOf: repeatElement("=", count: padlen))


if let data = Data(base64Encoded: base64String) ,
    let str = String(data: data, encoding: .utf8) 
    print(str) // "exp":1426822163,"id":"550b07738895600e99000001"

【讨论】:

最佳实践应该将 jwt 令牌存储在哪里?我一直在想它应该与用户名和密码一起存储到钥匙串中。 @user805981:我实际上对 jwt 令牌一无所知。但是,是的,密码等敏感数据应该存储在钥匙串中。 谢谢。关于钥匙扣。每个应用程序的钥匙串可以存储多少个钥匙串字典?每个应用程序是无限的还是一个密码钥匙串?【参考方案2】:

以上解决方案对我有用,我已转换为 swift3

这里可以找到swift3代码

var base64Str = arr[1] as String
if base64Str.characters.count % 4 != 0 
    let padlen = 4 - base64Str.characters.count % 4      
    base64Str += String(repeating: "=", count: padlen)


if let data = Data(base64Encoded: base64Str, options: []),
    let str = String(data: data, encoding: String.Encoding.utf8) 
        print(str)

【讨论】:

【参考方案3】:

Swift 4 如下:

if let data = Data(base64Encoded: base64String, options: []),
        let str = String(data: data as Data, encoding: String.Encoding.utf8) 
        print(str) // "exp":1426822163,"id":"550b07738895600e99000001"
    

【讨论】:

在 Swift 4 中,使用 Data 比使用 NSData 更好(使用 Data 比将 NSData 转换为 Data 更好)。 无论如何,@raju-abe 在他们的回答中已经给出了 Swift 3+ 的更新。请不要发布重复/不完整的内容。

以上是关于在 Swift 中解码 JSON Web 令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中解码 JWT(JSON Web 令牌)令牌?

解码 JSON Web 令牌 (Xamarin.Android)

无法解码 JSON Web 令牌

如何解码我在 Swift 中收到 REST API 的 JWT 令牌?

PHP JWT 与 JSON Web 令牌草案 11 兼容 [关闭]

Jwt 令牌解码 - Symfony 4