您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何打造基于s3cmd的短地址服務(wù)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“如何打造基于s3cmd的短地址服務(wù)”吧!
有線上項(xiàng)目使用S3去發(fā)布移動(dòng)端APP,因?yàn)樾枰鰴?quán)限認(rèn)證所以對(duì)應(yīng)的Object無法開“public-read”權(quán)限,嘗試使用Presign方式生成的簽名URL存在以下問題
生成的簽名URL地址包含敏感信息,會(huì)暴露bucket名稱和accesskey,帶來安全隱患。
生成的簽名URL地址太長,影響用戶體驗(yàn)。
生成的地址有效時(shí)間內(nèi)可以任意訪問,無法做到比較嚴(yán)格的反盜鏈。
使用openresty實(shí)現(xiàn)對(duì)S3數(shù)據(jù)訪問流程的封裝,客戶端的數(shù)據(jù)下載全部走openresty上面搭建的服務(wù),該服務(wù)提供一次性的短地址生成服務(wù)(訪問幾次以后對(duì)應(yīng)短地址失效),具體流程如下:
1. 用戶數(shù)據(jù)上傳到S3,并設(shè)置相應(yīng)Object權(quán)限為“public-read”,取得對(duì)應(yīng)的對(duì)外訪問URL。
2. 以之前生成的對(duì)外訪問URL為基礎(chǔ),生成對(duì)應(yīng)的短地址服務(wù)。
3. 客戶端使用短地址進(jìn)行訪問,超出訪問次數(shù)則無法訪問。
如果想進(jìn)一步提升安全性,可以將RGW和Openresty通過內(nèi)網(wǎng)互聯(lián),數(shù)據(jù)上傳全部走內(nèi)部網(wǎng)絡(luò),外部訪問走外網(wǎng)。
默認(rèn)openresty的lib路徑為/usr/local/openresty/lualib
需要依賴兩個(gè)lua文件,其中url.lua主要用于url地址的解析,redis_iresty.lua用于redis的連接
將下面的源碼文件保存為 /usr/local/openresty/lualib/resty/url.lua https://github.com/golgote/neturl/blob/master/lib/net/url.lua 將下面的源碼文件保存為 /usr/local/openresty/lualib/resty/redis_iresty.lua https://gist.github.com/moonbingbing/9915c66346e8fddcefb5
root@demohost:/etc/openresty# cat /etc/ceph/ceph.conf ... [client.radosgw.demo] rgw dns name = s3.cephbook.com #S3 endpoint對(duì)應(yīng)的域名 rgw frontends = "civetweb port=7480" host = demohost keyring = /etc/ceph/ceph.client.radosgw.keyring log file = /home/ceph/log/radosgw.log
root@demohost:/etc/openresty# cat /etc/openresty/nginx.conf ... server { listen 80; server_name ceph.vip; #短地址主機(jī)頭設(shè)置 location = /url { #生成短地址入口 content_by_lua_file /etc/openresty/url.lua; } location / { #提供短地址對(duì)應(yīng)的數(shù)據(jù)訪問 proxy_http_version 1.1; proxy_set_header Host $host; access_by_lua_file /etc/openresty/access.lua; proxy_pass http://127.0.0.1:7480; #對(duì)應(yīng)后端的radosgw服務(wù)入口 } }
生成短地址服務(wù)的源碼如下
root@demohost:/etc/openresty# cat url.lua local request_method = ngx.var.request_method local url_ = require "resty.url" #對(duì)應(yīng)之前的url庫 local redis = require "resty.redis_iresty" #對(duì)應(yīng)之前的redis_iresty庫 local s3_endpoint = "s3.cephbook.com" #這里設(shè)置只允許生成與S3 endpoint相關(guān)的短地址 local endpoint = s3_endpoint .. "$" local charset = {} for i = 48, 57 do table.insert(charset, string.char(i)) end for i = 65, 90 do table.insert(charset, string.char(i)) end for i = 97, 122 do table.insert(charset, string.char(i)) end function string.random(length) local urandom = assert(io.open('/dev/urandom','rb')) local a, b, c, d = urandom:read(4):byte(1,4) urandom:close() local seed = a*0x1000000 + b*0x10000 + c *0x100 + d math.randomseed(seed) if length > 0 then return string.random(length - 1) .. charset[math.random(1, #charset)] else return "" end end function genera_url(red,url_id,host,path) -- counts表示短地址最大訪問次數(shù),current表示當(dāng)前次數(shù) ok, err = red:hmset(url_id,'host',host,'uri',path,'counts',3,'current',1) if not ok then ngx.status = ngx.HTTP_METHOD_NOT_IMPLEMENTED ngx.say("failed to hmset: ", err) return ngx.exit(ngx.HTTP_METHOD_NOT_IMPLEMENTED) end -- 設(shè)置短地址記錄最多能夠在redis里面存儲(chǔ)的時(shí)長,避免資源耗盡 ok, err = red:expire(url_id,3600) if not ok then ngx.status = ngx.HTTP_METHOD_NOT_IMPLEMENTED ngx.say("failed to set expire: ", err) return ngx.exit(ngx.HTTP_METHOD_NOT_IMPLEMENTED) end end function get_info_by_id(red,url_id) ok, err = red:hgetall(url_id) if not ok then ngx.status = ngx.HTTP_SERVICE_UNAVAILABLE ngx.say("failed to getall : ", err) return ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE) end local h = red:array_to_hash(ok) return h end if request_method == "POST" then ngx.req.read_body() local data = ngx.req.get_body_data() local u = url_.parse(data) local hostname_check, hostname_err = ngx.re.match(u.host,endpoint) if not hostname_check then ngx.status = ngx.HTTP_BAD_REQUEST ngx.say("not a available s3_endpoint") ngx.exit(ngx.HTTP_BAD_REQUEST) end if u.host then if string.len(u.path) > 1 then local url_id = string.random(7) local red = redis:new() genera_url(red,url_id,u.host,u.path) local h = get_info_by_id(red,url_id) ngx.status = ngx.HTTP_CREATED ngx.say("ShortURL: ",ngx.var.scheme,"://",ngx.var.host,"/",url_id) ngx.say("host: ", h.host) ngx.say("uri: ", h.uri) ngx.say("counts: ", h.counts) ngx.say("current: ", h.current) ngx.exit(ngx.HTTP_CREATED) else ngx.status = ngx.HTTP_BAD_REQUEST ngx.say("path err") ngx.exit(ngx.HTTP_BAD_REQUEST) end else ngx.status = ngx.HTTP_BAD_REQUEST ngx.say("not a available url") ngx.exit(ngx.HTTP_BAD_REQUEST) end end
訪問短地址數(shù)據(jù)服務(wù)的源碼如下
root@demohost:/etc/openresty# cat /etc/openresty/access.lua local redis = require "resty.redis_iresty" local red = redis:new() local uri = ngx.var.uri local url_id = string.sub(uri,2,string.len(uri)) res, err = red:hgetall(url_id) if not res then ngx.exit(ngx.HTTP_NOT_FOUND) else local h = red:array_to_hash(res) -- 超出訪問次數(shù)則拒絕訪問,如果考慮資源占用可以自己加上刪除對(duì)應(yīng)redis記錄操作 if h.counts < h.current then ngx.status = ngx.HTTP_GONE ngx.say("current=",h.current," > counts=",h.counts) ngx.exit(ngx.HTTP_GONE) end ngx.req.set_header("host", h.host) ngx.req.set_uri(h.uri, false) ok, err = red:hincrby(url_id,'current',1) if not ok then ngx.status = ngx.HTTP_METHOD_NOT_IMPLEMENTED ngx.say("incrby key failed: ", err) ngx.exit(ngx.HTTP_METHOD_NOT_IMPLEMENTED) return end end
https://github.com/openresty/lua-nginx-module#http-status-constants
使用s3cmd或者是其他方式上傳文件,并設(shè)置對(duì)應(yīng)的Object訪問權(quán)限為"public-read"。
root@demohost:/tmp# s3cmd put myfile s3://demo --acl-public 'myfile' -> 's3://demo/myfile' [1 of 1] 21577 of 21577 100% in 0s 227.71 kB/s done 'myfile' -> 's3://demo/myfile' [1 of 1] 21577 of 21577 100% in 0s 203.11 kB/s done Public URL of the object is: http://demo.s3.cephbook.com/myfile
root@demohost:/tmp# curl ceph.vip/url -d "http://demo.s3.cephbook.com/myfile" -v * Hostname was NOT found in DNS cache * Connected to ceph.vip port 80 (#0) > POST /url HTTP/1.1 > User-Agent: curl/7.38.0 > Host: ceph.vip > Accept: */* > Content-Length: 29 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 29 out of 29 bytes < HTTP/1.1 201 Created * Server openresty/1.11.2.5 is not blacklisted < Server: openresty/1.11.2.5 < Date: Wed, 15 Nov 2017 09:56:14 GMT < Content-Type: application/octet-stream < Transfer-Encoding: chunked < Connection: keep-alive < ShortURL: http://ceph.vip/Vo3t5Ex #生成的短地址 host: demo.s3.cephbook.com uri: /myfile counts: 3 current: 1 * Connection #0 to host ceph.vip left intact
#訪問3次 root@demohost:/tmp# curl http://ceph.vip/Vo3t5Ex -v ... root@demohost:/tmp# curl http://ceph.vip/Vo3t5Ex -v ... root@demohost:/tmp# curl http://ceph.vip/Vo3t5Ex -v ... #第四次以后就不能訪問了 root@demohost:/tmp# curl http://ceph.vip/Vo3t5Ex -v * Hostname was NOT found in DNS cache * Trying ceph.vip... * Connected to ceph.vip (ceph.vip) port 80 (#0) > GET /Vo3t5Ex HTTP/1.1 > User-Agent: curl/7.38.0 > Host: ceph.vip > Accept: */* > < HTTP/1.1 410 Gone * Server openresty/1.11.2.5 is not blacklisted < Server: openresty/1.11.2.5 < Date: Wed, 15 Nov 2017 10:00:46 GMT < Content-Type: application/octet-stream < Transfer-Encoding: chunked < Connection: keep-alive < current=4 > counts=3 * Connection #0 to host ceph.vip left intact
感謝各位的閱讀,以上就是“如何打造基于s3cmd的短地址服務(wù)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)如何打造基于s3cmd的短地址服務(wù)這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。