From 455127e9e4d1c1f9fa01c0be608a4f57e244862f Mon Sep 17 00:00:00 2001 From: liubo Date: Tue, 26 Sep 2023 21:38:19 +0800 Subject: [PATCH] no message --- .gitignore | 1 + README.md | 41 ++------------ auth.js | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 32 +++++++++++ package.json | 21 +++++++ 5 files changed, 213 insertions(+), 37 deletions(-) create mode 100644 auth.js create mode 100644 index.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore index 1f22b9c..d9a1077 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* +node_modules \ No newline at end of file diff --git a/README.md b/README.md index 285825d..47dd275 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,4 @@ -# ks3-node-server-demo - -#### 介绍 -基于ks3-nodejs-sdk实现的后端服务 - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +### 说明 +该示例是用于android程序进行服务端签名时使用的,亦可提供给其他项目使用, + +>如果需要使用非nodejs语言实现,可自行参考签名流程实现相应语言程序 \ No newline at end of file diff --git a/auth.js b/auth.js new file mode 100644 index 0000000..9651d1a --- /dev/null +++ b/auth.js @@ -0,0 +1,155 @@ +var debug = require('debug')('auth'); +var crypto = require('crypto'); + +var encodeWithBase64 = function(s) { + var encodedStr = new Buffer(s).toString('base64'); + return encodedStr; +}; + +var hmacSha1 = function(encodedStr, sk) { + var hmac = crypto.createHmac('sha1', sk); + debug('over') + hmac.update(encodedStr); + return hmac.digest('base64'); +}; + + +var hmacMd5=function(encodedStr){ + var hmac = crypto.createHash('md5'); + hmac.update(encodedStr); + return hmac.digest('base64'); +}; + +/** + * 产生headers + * CanonicalizedKssHeaders + */ +function generateHeaders(header) { + var str = ''; + var arr = []; + + if(header){ + var prefix = 'x-kss'; + for(var it in header){ + // step1 : 所有`x-kss`的属性的键都转换为小写,值不变 + if(it.indexOf(prefix) == 0){ + arr.push((it.toLowerCase() +':'+header[it])); + } + } + // step2 : 根据属性名排序 + arr.sort(function (a, b) { + a = a.split(':')[0] + b = b.split(':')[0] + return a === b ? 0 : (a > b ? 1 : -1); + }); + // step3 : 拼接起来 + str = arr.join('\n'); + } + return str; +} + +/** + * + * 计算通过 HTTP 请求 Header 发送的签名 + */ +var generateToken = function(sk, req, body) { + debug('req:', req); + + var http_verb = req.method || 'GET'; + http_verb = http_verb.toUpperCase() + // Content-MD5, Content-Type, CanonicalizedKssHeaders可为空 + // Content-MD5 表示请求内容数据的MD5值, 使用Base64编码 + //var content_md5 = req.content_md5||''; + const md5 = req.headers && req.headers['Content-MD5'] + var content_md5 = md5 || ((!!req.body)?hmacMd5(req.body):''); + var content_type = (typeof req.type!== 'undefined') ? req.type : ''; + var canonicalized_Kss_Headers = generateHeaders(req.headers); + var canonicalized_Resource = req.resource || '/'; + if (canonicalized_Kss_Headers !== '') { + var string2Sign = http_verb + '\n' + content_md5 + '\n' + content_type + '\n' + (req.date) + '\n' + canonicalized_Kss_Headers + '\n' + canonicalized_Resource; + } else { + var string2Sign = http_verb + '\n' + content_md5 + '\n' + content_type + '\n' + (req.date) + '\n' + canonicalized_Resource; + } + debug('string2Sign:', string2Sign); + var digest = hmacSha1(string2Sign, sk); //已经经过了base64编码 + debug('digest:',digest); + return digest; +}; + +/** + * 基于StringToSign生成Signature + * @param sk + * @param stringToSign 经过Base64编码的policy + * @returns {*} + */ +var getSignature = function(sk, stringToSign) { + var signature = hmacSha1(stringToSign, sk); + return signature; +}; + + +/** + * 获取Authorization请求头的值 + * 计算通过 HTTP 请求 Header 发送的签名 + * @param ak + * @param sk + * @param req + * @param body + * @returns {string} + */ +var generateAuth = function(ak,sk,req, body) { + var token = generateToken(sk,req,body); + const auth = 'KSS '+ak+':'+ token; + return auth; +}; + +/** + * + * 通过 POST请求的表单实体发送的签名 + * @param sk {string} + * @param policy { Object或者String} ex. + * { + "expiration": "2016-02-02T12:12:00.000Z", + "conditions": [ + ["eq", "$bucket", 'bucket4jssdk'], + ["starts-with", "$key", ""], + ["starts-with", "$acl", "public-read"], + ["starts-with", "$name", ""] //post表单中默认会传name字段,故也需要加到policy中 + ] + }; + */ +var getFormSignature = function(sk, policy) { + if (Object.prototype.toString.call(policy) === '[object Object]') { + policy = JSON.stringify(policy) + } + var stringToSign = new Buffer(policy).toString('base64'); + var signature = getSignature(sk, stringToSign); + return signature; +}; + +/** + * 计算通过URL QueryString发送的签名 + * @param sk + * @param expires {number} 链接的过期时间,使用Unix_Time表示(s为单位) + * @param bucket bucket name + * @param object object key + */ +var getQueryStringSignature = function(sk, expires, bucket, object) { + var string2Sign = 'GET' + '\n\n\n' + expires + '\n' + '/' + bucket + '/' + object; + var signature = getSignature(sk, string2Sign); + return signature; +}; + + +function isKS3Callback(){} + +module.exports = { + hmacMd5, + generateHeaders : generateHeaders, + generateToken : generateToken, + generateAuth : generateAuth, + getSignature : getSignature, + getFormSignature : getFormSignature, + getQueryStringSignature : getQueryStringSignature +}; + diff --git a/index.js b/index.js new file mode 100644 index 0000000..093ac79 --- /dev/null +++ b/index.js @@ -0,0 +1,32 @@ + +var express = require('express'); +var auth = require('./auth'); +var app = express(); +// 替换成自己的AK和SK +var config = { + ak: process.env.AK, + sk: process.env.SK +} + + +app.use(express.json()) +app.post('/', function (request, response) { + const body = request.body; + console.log('request body:', body); + if (!body.headers) body.headers = {} + body.headers['Content-MD5'] = body.content_md5 + const date = body.date; + const req = { + method: body.http_method, + type: body.content_type, + resource: body.resource, + headers: body.headers, + date + } + var signature = auth.generateAuth(config.ak, config.sk, req, null); + response.send(signature); +}); + +app.listen(8000, function () { + console.log('----- ks3 sign server started. http://localhost:8000/ -----'); +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..0d8fdbf --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "ks3-signer-server", + "version": "1.0.0", + "description": "ks3 server client calculate sign authorization", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "ks3", + "server", + "sign" + ], + "author": "liubo15", + "license": "ISC", + "dependencies": { + "crypto": "^1.0.1", + "debug": "^4.3.4", + "express": "^4.18.2" + } +} -- Gitee