Aliyun OSS Nginx proxy module(阿里雲OSS Nginx 簽名代理模塊)

轉載.html

一、此文章主要介紹內容
本文主要介紹如何利用Nginx lua 實現將阿里雲OSS存儲空間作到同本地磁盤同樣使用。核心是利用Nginx lua 對OSS請求進行簽名並利用內部跳轉將全部訪問本地Nginx的請求加上OSS 簽名轉發給OSS,實現本地Nginx無縫銜接阿里雲OSS,存儲空間無限擴展,存儲成本無限降低,數據安全%99.99...... 。nginx

二、本篇文章使用到的一些工具技術及如何學習和獲取
一、luaweb

本文用到的都是一些基本的lua,基本上花半小時閱讀下lua的語法就能夠輕鬆理解本文內容docker

二、Nginx lua安全

主要是學習nginx lua 及環境部署,不過閱讀本文還不須要親自動手去學習及部署nginx lua 環境,讀者能夠從docker 官方鏡像源pull openresty 鏡像進行實驗。本文已openresty/1.7.7.2 做爲實驗環境。app

三、阿里雲OSScors

趕忙開通吧,用起來至關爽,一處存儲全球無限制訪問
https://www.aliyun.com/act/aliyun/ossdoc.html工具

四、參考博客學習

建議閱讀個人另一篇博客,對深刻理解OSS 及互聯網上提供的HTTP服務有更深入的理解
https://yq.aliyun.com/articles/7511?spm=0.0.0.0.IWbHSR阿里雲

三、利用Nginx lua 實現請求籤名並轉發至OSS
Lua 簽名 code
注:此代碼並不是出自做者之手
oss_auth.lua

-- has been sorted in alphabetical order
    local signed_subresources = {
       'acl',
       'append',
       'bucketInfo',
       'cname',
       'commitTransition',
       'comp',
       'cors',
       'delete',
       'lifecycle',
       'location',
       'logging',
       'mime',
       'notification',
       'objectInfo',
       'objectMeta',
       'partData',
       'partInfo',
       'partNumber',
       'policy',
       'position',
       'referer',
       'replication',
       'replicationLocation',
       'replicationProgress',
       'requestPayment',
       'response-cache-control',
       'response-content-disposition',
       'response-content-encoding',
       'response-content-language',
       'response-content-type',
       'response-expires',
       'restore',
       'security-token',
       'tagging',
       'torrent',
       'uploadId',
       'uploads',
       'versionId',
       'versioning',
       'versions',
       'website'
    }

    function string.startswith(s, start)
       return string.sub(s, 1, string.len(start)) == start
    end

    local function get_canon_sub_resource()
       local args = ngx.req.get_uri_args()
       -- lower keys
       local keys = {}
       for k, v in pairs(args) do
          keys[k:lower()] = v
       end
       -- make resource string
       local s = ''
       local sep = '?'
       for i, k in ipairs(signed_subresources) do
          v = keys[k]
          if v then
             -- sub table
             v = type(v) == 'table' and v[1] or v
             s = s .. string.format("%s%s=%s", sep, k, v)
             sep = '&'
          end
       end
       return s
    end

    local function get_canon_resource()
       resource = ''
       object = ngx.unescape_uri(ngx.var.uri)
       sub = get_canon_sub_resource()   
       return string.format("/%s%s%s", ngx.var.oss_bucket, object, sub)
    end   

    local function get_canon_headers()
       -- default: <lowerkey, value>
       local headers = ngx.req.get_headers()
       local keys = {}
       for k, v in pairs(headers) do
          if string.startswith(k, 'x-oss-') then
             -- client must assemble the same header keys
             if type(v) ~= 'string' then return nil end
             table.insert(keys, k)
          end
       end
       -- sorted in alphabetical order
       table.sort(keys)
       for i, key in ipairs(keys) do
          keys[i] = key .. ':' .. headers[key] .. '\n'
       end
       return table.concat(keys)
    end

    local function calc_sign(key, method, md5, type_, date, oss_headers, resource)
        -- string_to_sign:
        -- method + '\n' + content_md5 + '\n' + content_type + '\n'
        -- + date + '\n' + canonicalized_oss_headers + canonicalized_resource
        local sign_str = string.format('%s\n%s\n%s\n%s\n%s%s',
        method, md5, type_,
        date, oss_headers, resource)
        ngx.log(ngx.ERR, "SignStr:", sign_str, "\n")
        local sign_result = ngx.encode_base64(ngx.hmac_sha1(key, sign_str))
        return sign_result, sign_str
    end   

    local function oss_auth()
       -- ngx.log(ngx.INFO, 'auth')
       --local method = ngx.var.request_method
       local method = ngx.req.get_method()
       local content_md5 = ngx.var.http_content_md5 or ''
       local content_type = ngx.var.http_content_type or ''
       -- get date
       local date = ngx.var.http_x_oss_date or ngx.var.http_date or ''
       if date == '' then
          date = ngx.http_time(ngx.time())
          -- ngx.log(ngx.INFO, 'Date:', date)
          ngx.req.set_header('Date', date)
       end
       local resource = get_canon_resource()
       local canon_headers = get_canon_headers()
       local sign_result, sign_str = calc_sign(ngx.var.oss_auth_key, method, content_md5,
       content_type, date, canon_headers, resource)
       -- ngx.log(ngx.INFO, 'sign string:', sign_str)
       -- ngx.log(ngx.INFO, 'sign string len:', string.len(sign_str))
       local auth = string.format("OSS %s:%s", ngx.var.oss_auth_id, sign_result)
       ngx.req.set_header('Authorization', auth)
       ngx.exec("@oss")
    end   

    -- main
    res = oss_auth()

    if res then
       ngx.exit(res)
    end

nginx.conf

server {
        listen 8000;

        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_request_buffering off;

        location / {
            set $oss_bucket "your_oss_bucket";
            set $oss_auth_id "your_access_id";
            set $oss_auth_key "your_access_key";
            rewrite_by_lua_file "/path/oss_auth.lua";
        }

        # internal redirect
        location @oss {
            // endpoint eg: oss.aliyuncs.com
            proxy_pass http://your_oss_bucket.endpoint; 
        }
    }

、如何使用上述代碼
首先oss_auth.lua 無需作任何改動

nginx.conf 中須要將
your_oss_bucket 替換爲阿里雲OSS 的bucket名
your_access_id替換未AccessKeyId
your_access_key 替換爲 AccessKeySecret

例如:

error_log  logs/error.log  debug;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        lua_package_path "/usr/servers/lualib/?.lua;";
        lua_package_cpath "/usr/servers/lualib/?.so;"; 
        server {
            listen       80;
            location / {
                set $oss_bucket "bucket-example";
                set $oss_auth_id "za2127hbbdsdjhkhskel0ytocbzr";
                set $oss_auth_key "gMOG3o+JHDSJHCNMcsaH+Q=";
                rewrite_by_lua_file conf/lua/oss_auth.lua;
            }

            location @oss {
                proxy_pass http://bucket-example.oss-cn-qingdao.aliyuncs.com;
            }
        }
    }
相關文章
相關標籤/搜索