nginx 代理oss_Aliyun OSS Nginx proxy module(阿里云OSS Nginx 签名代理模块)

谭嘉容
2023-12-01

1、此文章主要介绍内容

本文主要介绍如何利用Nginx lua 实现将阿里云OSS存储空间做到同本地磁盘一样使用。核心是利用Nginx lua 对OSS请求进行签名并利用内部跳转将所有访问本地Nginx的请求加上OSS 签名转发给OSS,实现本地Nginx无缝衔接阿里云OSS,存储空间无限扩展,存储成本无限下降,数据安全%99.99...... 。

2、本篇文章使用到的一些工具技术及如何学习和获取

1、lua

本文用到的都是一些基本的lua,基本上花半小时阅读下lua的语法就可以轻松理解本文内容

2、Nginx lua

主要是学习nginx lua 及环境部署,不过阅读本文还不需要亲自动手去学习及部署nginx lua 环境,读者可以从docker 官方镜像源pull openresty 镜像进行实验。本文已openresty/1.7.7.2 作为实验环境。

3、阿里云OSS

4、参考博客

3、利用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:

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;

}

}

}

 类似资料: