我重构了 @Viktor Gardart 的代码
使用方法如下
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhY2NvdW56IiwianRpIjoiZTA0NGEyMTAtZjVmZi00Yjc2LWI2MzMtNTk0NjYzMWE0MjRjLWQxYTc3bXlpdGE0YnZnaG4yd2YiLCJleHAiOjE2NDk2NDI3MTF9.FO-AQhZ18qogsSbeTUY78EqhfL9xp9iUG3OlpOdxemE"
let jsonWebToken = JSONWebToken(jsonWebToken: token)
let expirationTime = jsonWebToken?.payload.expirationTime
JSONWebToken.swift
import Foundation
struct JSONWebToken {
let header: JSONWebTokenHeader
let payload: JSONWebTokenPayload
let signature: String
}
extension JSONWebToken {
init?(jsonWebToken: String) {
let encodedData = { (string: String) -> Data? in
var encodedString = string.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
switch (encodedString.utf16.count % 4) {
case 2: encodedString = "\(encodedString)=="
case 3: encodedString = "\(encodedString)="
default: break
}
return Data(base64Encoded: encodedString)
}
let components = jsonWebToken.components(separatedBy: ".")
guard components.count == 3,
let headerData = encodedData(components[0] as String),
let payloadData = encodedData(components[1] as String) else { return nil }
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
header = try decoder.decode(JSONWebTokenHeader.self, from: headerData)
payload = try decoder.decode(JSONWebTokenPayload.self, from: payloadData)
signature = components[2] as String
} catch {
print(error.localizedDescription)
return nil
}
}
}
JSONWebTokenHeader.swift
import Foundation
struct JSONWebTokenHeader {
let type: String
let algorithm: String
}
extension JSONWebTokenHeader: Codable {
private enum Key: String, CodingKey {
case type = "typ"
case algorithm = "alg"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: Key.self)
do { try container.encode(type, forKey: .type) } catch { throw error }
do { try container.encode(algorithm, forKey: .algorithm) } catch { throw error }
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
do { type = try container.decode(String.self, forKey: .type) } catch { throw error }
do { algorithm = try container.decode(String.self, forKey: .algorithm) } catch { throw error }
}
}
JSONWebTokenPayload.swift
import Foundation
struct JSONWebTokenPayload {
let issuer: String
let expirationTime: Double
let jsonWebTokenID: String
}
extension JSONWebTokenPayload: Codable {
private enum Key: String, CodingKey {
case issuer = "iss"
case expirationTime = "exp"
case jsonWebTokenID = "jti"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: Key.self)
do { try container.encode(issuer, forKey: .issuer) } catch { throw error }
do { try container.encode(expirationTime, forKey: .expirationTime) } catch { throw error }
do { try container.encode(jsonWebTokenID, forKey: .jsonWebTokenID) } catch { throw error }
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
do { issuer = try container.decode(String.self, forKey: .issuer) } catch { throw error }
do { expirationTime = try container.decode(Double.self, forKey: .expirationTime) } catch { throw error }
do { jsonWebTokenID = try container.decode(String.self, forKey: .jsonWebTokenID) } catch { throw error }
}
}