swift 添加JWT验证

简要

因项目请求安全问题,需要加入JWT验证,而相关的文档上给出的说明都是sh256的加密方式,但是对应道swift中或者OC中加密出来的终是与服务器验证通不过,很恼火,网上各种说法,以及代码,坑特别多
此地的sha256加密不纯粹是HMACSHa256加密,若是网上单纯的HMACSHa256加密,那你就进入误区,出不来了。
还有一个就是base64UrlEncode转码后的符号转换问题,不是所有的符号都转换为下横线(_)的切记切记

什么是JSON Web令牌?

JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑和自包含的方式,用于将各方之间安全地将信息作为JSON对象传输。这些信息可以被验证和信任,因为它是数字签名的。JWT可以使用秘密(使用HMAC算法)或使用RSAECDSA对公钥/私钥对进行签名。

虽然JWT可以加密,以提供各方之间的保密性,但我们将专注于签名令牌。签名令牌可以验证其中包含的索赔的完整性,而加密令牌则向其他方隐藏这些索赔。当令牌使用公钥/私钥对签名时,签名还证明只有持有私钥的一方才是签署私钥的一方。

您应该何时使用JSON Web令牌?

以下是JSON Web令牌有用的一些场景:

  • 授权:这是使用JWT最常见的场景。用户登录后,每个后续请求都将包括JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是目前广泛使用JWT的一项功能,因为它的开销很小,并且能够轻松在不同领域使用。
  • 信息交换:JSON Web令牌是各方之间安全传输信息的好方法。因为JWT可以签名——例如,使用公钥/私钥对——您可以确定发件人就是他们所说的那个人。此外,由于签名是使用标题和有效负载计算的,您还可以验证内容是否未被篡改。

JSON Web令牌结构是什么?

JSON Web令牌以紧凑的形式由三个部分组成,由点(.)分隔,即:

  • 标题
  • 有效载荷
  • 签名

因此,JWT通常如下所示。

xxxxx.yyyyy.zzzzz

标题header

标头通常由两部分组成:令牌的类型(即JWT)和使用的签名算法(如HMAC SHA256或RSA)。

例如:

{
  "alg": "HS256",
  "typ": "JWT"
}
#注意 若是其他加密方式 替换 alg

然后,此JSON是Base64Url编码的,以形成JWT的第一部分。

有效载荷payload

令牌的第二部分是有效负载,其中包含索赔。索赔是关于实体(通常是用户)和其他数据的陈述。有三种类型的索赔:注册索赔、公共索赔和私人索赔。

也就是鉴权信息实体

{
  "uid": "20210001",
  "source": "ios",
  "token": "7ab8baac69b518faccc78***d5ee9cba",
  "exp": 1636290555
}
#根据实际情况,各自需求

然后对有效负载进行Base64Url编码,以形成JSON Web令牌的第二部分。

请注意,对于签名令牌,这些信息虽然可以防止篡改,但任何人都可以阅读。除非加密,否则不要将秘密信息放入JWT的有效负载或标头元素中。

签名autograph

要创建签名部分,您必须使用编码标头、编码有效负载、秘密、标头中指定的算法并签名。

例如,如果您想使用HMAC SHA256算法,签名将以以下方式创建:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

注意

1.此地的 HMACSHA256方法在swift中是没有的,所以需要自己定义,方法如下
2. header与payload都要转换为base64UrlEncode
base64 与 base64UrlEncode 虽然都是string 但是不是一个东西
extension Dictionary {
    /// 字典转换为data
    /// - Returns: data
    func toData() -> Data? {
        if !JSONSerialization.isValidJSONObject(self) {
            return nil
        }
        do {
            let data = try JSONSerialization.data(withJSONObject: self, options: [])
            return data
        } catch let error {
            DLog(error.localizedDescription)
            return nil
        }
    }
    func base64String()->String{
      return  ((toData()?.base64EncodedString() ?? "")).replacingOccurrences(of: "+", with: "-")
            .replacingOccurrences(of: "/", with: "_")
            .replacingOccurrences(of: "=", with: "")
    }
}



import CommonCrypto
enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5: result = kCCHmacAlgMD5
        case .SHA1: result = kCCHmacAlgSHA1
        case .SHA224: result = kCCHmacAlgSHA224
        case .SHA256: result = kCCHmacAlgSHA256
        case .SHA384: result = kCCHmacAlgSHA384
        case .SHA512: result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }

    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5: result = CC_MD5_DIGEST_LENGTH
        case .SHA1: result = CC_SHA1_DIGEST_LENGTH
        case .SHA224: result = CC_SHA224_DIGEST_LENGTH
        case .SHA256: result = CC_SHA256_DIGEST_LENGTH
        case .SHA384: result = CC_SHA384_DIGEST_LENGTH
        case .SHA512: result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {
    func jwtHmac(algorithm: CryptoAlgorithm, key: String) -> String {
        guard let dataAB = data(using: .utf8, allowLossyConversion: false),
              let datas = key.data(using: .utf8, allowLossyConversion: false) else {
            return ""
        }

        let ctx = UnsafeMutablePointer<CCHmacContext>.allocate(capacity: 1)
        defer { ctx.deallocate() }
        datas.withUnsafeBytes({ CCHmacInit(ctx, algorithm.HMACAlgorithm, $0.baseAddress, size_t(datas.count)) })
        dataAB.withUnsafeBytes({ CCHmacUpdate(ctx, $0.baseAddress, size_t(dataAB.count)) })
        var hmac = Array<UInt8>(repeating: 0, count: algorithm.digestLength)
        CCHmacFinal(ctx, &hmac)

        let strHmac = Data(hmac).base64EncodedString().replacingOccurrences(of: "+", with: "-").replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "=", with: "")
        return strHmac
    }
}

使用方法:

      #根据你实际的需求来操作
            let dic:[String:Any] = [
                "sub": "1234567890",
                "name":"John Doe",
                "iat":1516239022,
            ]
           
          #得到 base64UrlEncode
            let playload = dic.base64String()
            #得到 base64UrlEncode
            let header = ["typ":"JWT","alg":"HS256"].base64String()
            #拼接 以(.)隔开
            let strAB = "\(header).\(playload)"
          # 根据服务器给的密钥进行加密 
            let sha256 = strAB.jwtHmac(algorithm: .SHA256, key: APPJWt)
            #拼接 以(.)隔开
            let autograph = (strAB + "." + sha256)
           #得到发送给服务器的三段式如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
            headers.add(name: "Member", value: autograph)

JWT官网有详细的介绍

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容