mirror of
https://github.com/wahyd4/ruby-sdk.git
synced 2026-08-09 21:06:19 +10:00
Merge pull request #84 from BluntBlade/master
重写与授权相关的函数和类,并归入Qiniu::Auth空间。
This commit is contained in:
@@ -7,7 +7,6 @@ rvm:
|
||||
- 2.1.1
|
||||
- jruby-18mode
|
||||
- jruby-19mode
|
||||
- jruby-head
|
||||
- ree
|
||||
before_script:
|
||||
- export QINIU_ACCESS_KEY=LGRqJsjX7LAvtdtX6hhyxs861lS57HwnOQmJsOuX
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
## CHANGE LOG
|
||||
|
||||
### v6.2.0
|
||||
|
||||
- 重写与授权相关的函数并归入Qiniu::Auth空间,原授权凭证生成类维持不变。
|
||||
|
||||
- 添加Qiniu::Storage::PutPolicy类和Qiniu::Storage#upload_with_put_policy方法,并推荐使用两者组合实现单文件上传。
|
||||
|
||||
### v6.1.0
|
||||
|
||||
- Qiniu::Storage所有上传接口返回第三个值raw_headers,类型为Hash,包含已解析的HTTP响应报文中的所有Header信息。
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
qiniu (6.1.0)
|
||||
qiniu (6.2.0)
|
||||
json (~> 1.7)
|
||||
mime-types (~> 1.19)
|
||||
rest-client (~> 1.6)
|
||||
|
||||
+215
-2
@@ -1,17 +1,146 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# vim: sw=2 ts=2
|
||||
|
||||
require 'hmac-sha1'
|
||||
require 'uri'
|
||||
|
||||
require 'qiniu/exceptions'
|
||||
|
||||
module Qiniu
|
||||
module Auth
|
||||
DEFAULT_AUTH_SECONDS = 3600
|
||||
|
||||
class << self
|
||||
def calculate_deadline(expires_in, deadline = nil)
|
||||
### 授权期计算
|
||||
if expires_in.is_a?(Integer) && expires_in > 0 then
|
||||
# 指定相对时间,单位:秒
|
||||
return Time.now.to_i + expires_in
|
||||
elsif deadline.is_a?(Integer) then
|
||||
# 指定绝对时间,常用于调试和单元测试
|
||||
return deadline
|
||||
end
|
||||
|
||||
# 默认授权期1小时
|
||||
return Time.now.to_i + DEFAULT_AUTH_SECONDS
|
||||
end # calculate_deadline
|
||||
end # class << self
|
||||
|
||||
class PutPolicy
|
||||
private
|
||||
def initialize(bucket,
|
||||
key = nil,
|
||||
expires_in = DEFAULT_AUTH_SECONDS,
|
||||
deadline = nil)
|
||||
### 设定scope参数(必填项目)
|
||||
self.scope!(bucket, key)
|
||||
|
||||
### 设定deadline参数(必填项目)
|
||||
@expires_in = expires_in
|
||||
@deadline = Auth.calculate_deadline(expires_in, deadline)
|
||||
end # initialize
|
||||
|
||||
PARAMS = {
|
||||
# 字符串类型参数
|
||||
:scope => "scope" ,
|
||||
:save_key => "saveKey" ,
|
||||
:end_user => "endUser" ,
|
||||
:return_url => "returnUrl" ,
|
||||
:return_body => "returnBody" ,
|
||||
:callback_url => "callbackUrl" ,
|
||||
:callback_body => "callbackBody" ,
|
||||
:persistent_ops => "persistentOps" ,
|
||||
:persistent_notify_url => "persistentNotifyUrl" ,
|
||||
:transform => "transform" ,
|
||||
|
||||
# 数值类型参数
|
||||
:deadline => "deadline" ,
|
||||
:insert_only => "insertOnly" ,
|
||||
:fsize_limit => "fsizeLimit" ,
|
||||
:detect_mime => "detectMime" ,
|
||||
:mime_limit => "mimeLimit" ,
|
||||
:fop_timeout => "fopTimeout"
|
||||
} # PARAMS
|
||||
|
||||
public
|
||||
attr_reader :bucket, :key
|
||||
|
||||
def scope!(bucket, key = nil)
|
||||
@bucket = bucket
|
||||
@key = key
|
||||
|
||||
if key.nil? then
|
||||
# 新增语义,文件已存在则失败
|
||||
@scope = bucket
|
||||
else
|
||||
# 覆盖语义,文件已存在则直接覆盖
|
||||
@scope = "#{bucket}:#{key}"
|
||||
end
|
||||
end # scope!
|
||||
|
||||
def expires_in!(seconds)
|
||||
if !seconds.nil? then
|
||||
return @expires_in
|
||||
end
|
||||
|
||||
@epires_in = seconds
|
||||
@deadline = Auth.calculate_deadline(seconds)
|
||||
|
||||
return @expires_in
|
||||
end # expires_in!
|
||||
|
||||
def expires_in=(seconds)
|
||||
return expires_in!(seconds)
|
||||
end # expires_in=
|
||||
|
||||
def expires_in
|
||||
return @expires_in
|
||||
end # expires_in
|
||||
|
||||
def allow_mime_list! (list)
|
||||
@mime_limit = list
|
||||
end # allow_mime_list!
|
||||
|
||||
def deny_mime_list! (list)
|
||||
@mime_limit = "!#{list}"
|
||||
end # deny_mime_list!
|
||||
|
||||
def insert_only!
|
||||
@insert_only = 1
|
||||
end # insert_only!
|
||||
|
||||
def detect_mime!
|
||||
@detect_mime = 1
|
||||
end # detect_mime!
|
||||
|
||||
def to_json
|
||||
args = {}
|
||||
|
||||
PARAMS.each_pair do |key, fld|
|
||||
val = self.__send__(key)
|
||||
if !val.nil? then
|
||||
args[fld] = val
|
||||
end
|
||||
end
|
||||
|
||||
return args.to_json
|
||||
end # to_json
|
||||
|
||||
PARAMS.each_pair do |key, fld|
|
||||
attr_accessor key
|
||||
end
|
||||
end # class PutPolicy
|
||||
|
||||
class << self
|
||||
|
||||
include Utils
|
||||
|
||||
def call_with_signature(url, data, retry_times = 0, options = {})
|
||||
code, data, raw_headers = http_request url, data, options.merge({:qbox_signature_token => generate_qbox_signature(url, data, options[:mime])})
|
||||
[code, data, raw_headers]
|
||||
return Utils.http_request(
|
||||
url,
|
||||
data,
|
||||
options.merge({:qbox_signature_token => generate_acctoken(url, data)})
|
||||
)
|
||||
end # call_with_signature
|
||||
|
||||
def request(url, data = nil, options = {})
|
||||
@@ -19,6 +148,90 @@ module Qiniu
|
||||
[code, data, raw_headers]
|
||||
end # request
|
||||
|
||||
EMPTY_ARGS = {}
|
||||
|
||||
### 生成下载授权URL
|
||||
def authorize_download_url(url, args = EMPTY_ARGS)
|
||||
### 提取AK/SK信息
|
||||
access_key = Config.settings[:access_key]
|
||||
secret_key = Config.settings[:secret_key]
|
||||
|
||||
### 授权期计算
|
||||
e = Auth.calculate_deadline(args[:expires_in], args[:deadline])
|
||||
|
||||
### URL变换:追加授权期参数
|
||||
if url.index('?').is_a?(Fixnum) then
|
||||
# 已有参数
|
||||
download_url = "#{url}&e=#{e}"
|
||||
else
|
||||
# 尚无参数
|
||||
download_url = "#{url}?e=#{e}"
|
||||
end
|
||||
|
||||
### 生成数字签名
|
||||
sign = HMAC::SHA1.new(secret_key).update(download_url).digest
|
||||
encoded_sign = Utils.urlsafe_base64_encode(sign)
|
||||
|
||||
### 生成下载授权凭证
|
||||
dntoken = "#{access_key}:#{encoded_sign}"
|
||||
|
||||
### 返回下载授权URL
|
||||
return "#{download_url}&token=#{dntoken}"
|
||||
end # authorize_download_url
|
||||
|
||||
def generate_acctoken(url, body = '')
|
||||
### 提取AK/SK信息
|
||||
access_key = Config.settings[:access_key]
|
||||
secret_key = Config.settings[:secret_key]
|
||||
|
||||
### 解析URL,生成待签名字符串
|
||||
uri = URI.parse(url)
|
||||
signing_str = uri.path
|
||||
|
||||
# 如有QueryString部分,则需要加上
|
||||
query_string = uri.query
|
||||
if query_string.is_a?(String) && !query_string.empty?
|
||||
signing_str += '?' + query_string
|
||||
end
|
||||
|
||||
# 追加换行符
|
||||
signing_str += "\n"
|
||||
|
||||
# 如果有Body,则也加上
|
||||
# (仅限于mime == "application/x-www-form-urlencoded"的情况)
|
||||
if body.is_a?(String) && !body.empty?
|
||||
signing_str += body
|
||||
end
|
||||
|
||||
### 生成数字签名
|
||||
sign = HMAC::SHA1.new(secret_key).update(signing_str).digest
|
||||
encoded_sign = Utils.urlsafe_base64_encode(sign)
|
||||
|
||||
### 生成管理授权凭证
|
||||
acctoken = "#{access_key}:#{encoded_sign}"
|
||||
|
||||
### 返回管理授权凭证
|
||||
return acctoken
|
||||
end # generate_acctoken
|
||||
|
||||
def generate_uptoken(put_policy)
|
||||
### 提取AK/SK信息
|
||||
access_key = Config.settings[:access_key]
|
||||
secret_key = Config.settings[:secret_key]
|
||||
|
||||
### 生成待签名字符串
|
||||
encoded_put_policy = Utils.urlsafe_base64_encode(put_policy.to_json)
|
||||
|
||||
### 生成数字签名
|
||||
sign = HMAC::SHA1.new(secret_key).update(encoded_put_policy).digest
|
||||
encoded_sign = Utils.urlsafe_base64_encode(sign)
|
||||
|
||||
### 生成上传授权凭证
|
||||
uptoken = "#{access_key}:#{encoded_sign}:#{encoded_put_policy}"
|
||||
|
||||
### 返回上传授权凭证
|
||||
return uptoken
|
||||
end # generate_uptoken
|
||||
end # class << self
|
||||
|
||||
end # module Auth
|
||||
|
||||
+13
-2
@@ -9,10 +9,21 @@ module Qiniu
|
||||
Auth.request Config.settings[:rs_host] + '/buckets'
|
||||
end # buckets
|
||||
|
||||
def mkbucket(bucket_name)
|
||||
Auth.request Config.settings[:rs_host] + '/mkbucket/' + bucket_name
|
||||
PRIVATE_BUCKET = 0
|
||||
PUBLIC_BUCKET = 1
|
||||
|
||||
def mkbucket(bucket_name, is_public = PUBLIC_BUCKET)
|
||||
Auth.request Config.settings[:rs_host] + '/mkbucket2/' + bucket_name + '/public/' + is_public.to_s
|
||||
end # mkbucket
|
||||
|
||||
def make_a_private_bucket(bucket_name)
|
||||
return mkbucket(bucket_name, PRIVATE_BUCKET)
|
||||
end # make_a_private_bucket
|
||||
|
||||
def make_a_public_bucket(bucket_name)
|
||||
return mkbucket(bucket_name, PUBLIC_BUCKET)
|
||||
end # make_a_public_bucket
|
||||
|
||||
def stat(bucket, key)
|
||||
Auth.request Config.settings[:rs_host] + '/stat/' + encode_entry_uri(bucket, key)
|
||||
end # stat
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# vim: sw=2 ts=2
|
||||
|
||||
module Qiniu
|
||||
module Storage
|
||||
@@ -61,6 +62,27 @@ module Qiniu
|
||||
Utils.http_request url, post_data
|
||||
end # upload_with_token_2
|
||||
|
||||
### 授权举例
|
||||
# put_policy.bucket | put_policy.key | key | 语义 | 授权
|
||||
# :---------------- | :------------- | :------ | :--- | :---
|
||||
# trivial_bucket | <nil> | <nil> | 新增 | 允许,最终key为1)使用put_policy.save_key生成的值或2)资源内容的Hash值
|
||||
# trivial_bucket | <nil> | foo.txt | 新增 | 允许
|
||||
# trivial_bucket | <nil> | bar.jpg | 新增 | 允许
|
||||
# trivial_bucket | foo.txt | <nil> | 覆盖 | 允许,由SDK将put_policy.key赋值给key实现
|
||||
# trivial_bucket | foo.txt | foo.txt | 覆盖 | 允许
|
||||
# trivial_bucket | foo.txt | bar.jpg | 覆盖 | 禁止,put_policy.key与key不一致
|
||||
def upload_with_put_policy(put_policy,
|
||||
local_file,
|
||||
key = nil,
|
||||
x_vars = nil)
|
||||
uptoken = Auth.generate_uptoken(put_policy)
|
||||
if key.nil? then
|
||||
key = put_policy.key
|
||||
end
|
||||
|
||||
return upload_with_token_2(uptoken, local_file, key, x_vars)
|
||||
end # upload_with_put_policy
|
||||
|
||||
private
|
||||
def _generate_action_params(local_file,
|
||||
bucket,
|
||||
|
||||
@@ -128,26 +128,5 @@ module Qiniu
|
||||
File.open(filepath, "rb") { |f| Zlib.crc32 f.read }
|
||||
end
|
||||
|
||||
def generate_qbox_signature(url, params, mime = nil)
|
||||
access_key = Config.settings[:access_key]
|
||||
secret_key = Config.settings[:secret_key]
|
||||
uri = URI.parse(url)
|
||||
signature = uri.path
|
||||
query_string = uri.query
|
||||
signature += '?' + query_string if !query_string.nil? && !query_string.empty?
|
||||
signature += "\n"
|
||||
if params.is_a?(Hash)
|
||||
params_string = generate_query_string(params)
|
||||
signature += params_string
|
||||
end
|
||||
if mime.is_a?(String) && mime == "application/x-www-form-urlencoded" && params.is_a?(String)
|
||||
signature += params
|
||||
end
|
||||
hmac = HMAC::SHA1.new(secret_key)
|
||||
hmac.update(signature)
|
||||
encoded_digest = urlsafe_base64_encode(hmac.digest)
|
||||
%Q(#{access_key}:#{encoded_digest})
|
||||
end
|
||||
|
||||
end # module Utils
|
||||
end # module Qiniu
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
module Qiniu
|
||||
module Version
|
||||
MAJOR = 6
|
||||
MINOR = 1
|
||||
MINOR = 2
|
||||
PATCH = 0
|
||||
# Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
|
||||
#
|
||||
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
require 'spec_helper'
|
||||
require 'qiniu/auth'
|
||||
require 'qiniu/storage'
|
||||
require 'digest/sha1'
|
||||
|
||||
module Qiniu
|
||||
module Auth
|
||||
describe Auth do
|
||||
|
||||
before :all do
|
||||
@bucket = 'RubySDK-Test-Private'
|
||||
@bucket = make_unique_bucket(@bucket)
|
||||
|
||||
### 尝试创建Bucket
|
||||
result = Qiniu::Storage.make_a_private_bucket(@bucket)
|
||||
puts result.inspect
|
||||
end
|
||||
|
||||
after :all do
|
||||
### 不删除Bucket以备下次使用
|
||||
end
|
||||
|
||||
### 测试私有资源下载
|
||||
context ".download_private_file" do
|
||||
it "should works" do
|
||||
### 生成Key
|
||||
key = 'a_private_file'
|
||||
key = make_unique_key_in_bucket(key)
|
||||
puts "key=#{key}"
|
||||
|
||||
### 上传测试文件
|
||||
pp = Auth::PutPolicy.new(@bucket, key)
|
||||
code, data, raw_headers = Qiniu::Storage.upload_with_put_policy(
|
||||
pp,
|
||||
__FILE__
|
||||
)
|
||||
code.should == 200
|
||||
puts data.inspect
|
||||
puts raw_headers.inspect
|
||||
|
||||
### 获取下载地址
|
||||
code, data = Qiniu::Storage.get(@bucket, key)
|
||||
code.should == 200
|
||||
puts data.inspect
|
||||
|
||||
url = data['url']
|
||||
|
||||
### 授权下载地址(不带参数)
|
||||
download_url = Qiniu::Auth.authorize_download_url(url)
|
||||
puts "download_url=#{download_url}"
|
||||
|
||||
result = RestClient.get(download_url)
|
||||
result.code.should == 200
|
||||
result.body.should_not be_empty
|
||||
|
||||
### 授权下载地址(带参数)
|
||||
download_url = Qiniu::Auth.authorize_download_url(url + '?download/a.m3u8')
|
||||
puts "download_url=#{download_url}"
|
||||
|
||||
result = RestClient.get(download_url)
|
||||
result.code.should == 200
|
||||
result.body.should_not be_empty
|
||||
|
||||
### 删除文件
|
||||
code, data = Qiniu::Storage.delete(@bucket, key)
|
||||
code.should == 200
|
||||
puts data.inspect
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end # module Storage
|
||||
end # module Qiniu
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# vim: sw=2 ts=2
|
||||
|
||||
require 'digest/sha1'
|
||||
require 'spec_helper'
|
||||
@@ -29,15 +30,12 @@ module Qiniu
|
||||
end
|
||||
|
||||
### 准备数据
|
||||
context ".upload_with_token_2" do
|
||||
context ".prepare_file" do
|
||||
it "should works" do
|
||||
upopts = {:scope => @bucket, :expires_in => 3600, :endUser => "why404@gmail.com"}
|
||||
uptoken = Qiniu.generate_upload_token(upopts)
|
||||
|
||||
code, data, raw_headers = Qiniu::Storage.upload_with_token_2(
|
||||
uptoken,
|
||||
__FILE__,
|
||||
@key
|
||||
pp = Auth::PutPolicy.new(@bucket, @key)
|
||||
code, data, raw_headers = Qiniu::Storage.upload_with_put_policy(
|
||||
pp,
|
||||
__FILE__
|
||||
)
|
||||
code.should == 200
|
||||
puts data.inspect
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# vim: sw=2 ts=2
|
||||
|
||||
require 'spec_helper'
|
||||
require 'qiniu/auth'
|
||||
@@ -126,6 +127,49 @@ module Qiniu
|
||||
end
|
||||
end
|
||||
|
||||
context ".upload_with_put_policy" do
|
||||
it "should works" do
|
||||
pp = Qiniu::Auth::PutPolicy.new(@bucket, @key)
|
||||
pp.end_user = "why404@gmail.com"
|
||||
puts 'put_policy=' + pp.to_json
|
||||
|
||||
code, data, raw_headers = Qiniu::Storage.upload_with_put_policy(
|
||||
pp,
|
||||
__FILE__,
|
||||
@key + '-not-equal'
|
||||
)
|
||||
code.should_not == 200
|
||||
puts data.inspect
|
||||
puts raw_headers.inspect
|
||||
|
||||
code, data, raw_headers = Qiniu::Storage.upload_with_put_policy(
|
||||
pp,
|
||||
__FILE__,
|
||||
@key
|
||||
)
|
||||
|
||||
code.should == 200
|
||||
puts data.inspect
|
||||
puts raw_headers.inspect
|
||||
end
|
||||
end # .upload_with_put_policy
|
||||
|
||||
context ".stat" do
|
||||
it "should exists" do
|
||||
code, data = Qiniu::Storage.stat(@bucket, @key)
|
||||
puts data.inspect
|
||||
code.should == 200
|
||||
end
|
||||
end
|
||||
|
||||
context ".delete" do
|
||||
it "should works" do
|
||||
code, data = Qiniu::Storage.delete(@bucket, @key)
|
||||
puts data.inspect
|
||||
code.should == 200
|
||||
end
|
||||
end
|
||||
|
||||
### 测试断点续上传
|
||||
context ".resumable_upload_with_token" do
|
||||
it "should works" do
|
||||
|
||||
Reference in New Issue
Block a user