在 iOS App 中使用七牛的存储服务

在 iOS App 中使用七牛的存储服务

最近,在做一个需要存储文件的应用,自然就先分析和测试了各种云存储的方案,刚开始用是的是阿里云的OSS,不得不说,他们的SDK开发的确实不错,使用起来很容易,但是,他们没有免费的流量,就在我测试的过程中,就产生了一些小的费用,后来我就在考虑一些有免费流量的存储,自然国内的另一提供存储方案的被我发现了——七牛,他每个月有很多的流量,足够个人使用了。但是,他的移动客户端 SDK 开发的是一个阉割版,只能上传,不能管理和下载等。

官方的文档中有很明确的提示:为了防止申请的AccessKey和AccessSecret在客户端泄露,因为别人反编译自己的App,可能会获得自己的秘钥,所以官方做了阉割。建议服务器端返回。

但是,作为一个个人开发者,不想开发太高级的功能,只是想存储一些资源,在App访问,还要建一个服务器,也太坑了,那么这篇文章就是要通过Swift在iOS中生成token。

创建工程

iOS 基本的创建工程不别说,接着使用Pod导入需要使用的包,有两个:

  • QIniu
  • JSONKit-NoWarning
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
use_frameworks!


pod 'JSONKit-NoWarning'
pod 'Qiniu'

执行:pod update 后,双击打开项目名称.xcworkspace

好了,我们的基础工程已经建立了。

分析需求

七牛的文档写的确实不怎么样,我是研究了好久才从坑中爬出来的。

七牛的 token 有三种,分别是:

  • 管理策略 token
  • 上传策略 token
  • 下载策略 url后面需要带签名

管理策略

管理策略是我这一次需要用到的,我准备将我的Bucket中的资源列举出来。

// 管理 Token
func managerToken(url: NSURL, content: String?, contentType: String) -> String {
    // 请求内容
    var signingStr = ""
    if let path = url.path {
        signingStr += path
    }
    if let query = url.query {
        signingStr += "?" + query
    }
    signingStr += "\n"
    if contentType == "application/x-www-form-urlencoded" {
        if let data = content {
            signingStr += data
        }
    }
    // sign
    let token = sign(signingStr)
    return token
}

// 上传 Token
func uploadToken(bucket: String, fileName: String?) -> String {
    let authInfo = NSMutableDictionary(capacity: 3);
    // bucket name
    authInfo.setValue(bucket, forKey: "scope")
    // time
    let oneHourLater = NSDate().timeIntervalSince1970 + 3600
    print(NSDate(timeIntervalSince1970: NSTimeInterval(oneHourLater)))
    authInfo.setValue(NSNumber(longLong: Int64(oneHourLater)), forKey: "deadline")
    let token = signWithData(authInfo.JSONString())
    return token
}

// 下载 Url
func downLoadURL(url: String, expires: Int64 = 3600) -> String {
    let deadline = Int64(NSDate().timeIntervalSince1970) + expires
    var downURL = url + "?" + "e=\(deadline)"
    downURL += "&token=" + self.sign(downURL)
    return downURL
}

// MARK: 内部方法

// KeyID:HMAC:SIGN
private func signWithData(data: String) -> String {
    let encodedData = QNUrlSafeBase64.encodeString(data)
    return sign(encodedData) + ":" + encodedData
}

// KeyID:DATA
private func sign(data: String) -> String {
    let hmac = self.HMACSHA1(data)
    return kAccessKeyID + ":" + hmac
}

// SHA1 编码
private func HMACSHA1(text: String) -> String {

    var result: [CUnsignedChar]
    if let cKey = kAccessKeySecret.cStringUsingEncoding(NSASCIIStringEncoding),
        cData = text.cStringUsingEncoding(NSASCIIStringEncoding)
    {
        let algo = CCHmacAlgorithm(kCCHmacAlgSHA1)
        result = Array(count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
        CCHmac(algo, cKey, cKey.count - 1, cData, cData.count - 1, &result)
    } else {
        return ""
    }
    let HMAC = NSData(bytes: result, length: Int(CC_SHA1_DIGEST_LENGTH))
    let hash = QNUrlSafeBase64.encodeData(HMAC)
    return hash
}

上面就是这一次的所有核心代码。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注