浏览器中生成 OSS 令牌 | Web Crypto API
笔者写文章的时候,都会把图片通过自己搭建的一个简单站点 https://imgbed.sugarat.top/ 把图片上传到各种云的对象存储服务(OSS)上。
然后通过CDN访问,保证图片有可靠的访问速度和质量。
本着尽可能简单,减少对后端依赖的原则,上传令牌是在本地(Node.js)生成并设置一个过期时间,在浏览器中直接粘贴,存放在 LocalStorage 中,过期就在本地重新生成一次就行。
但现在生成的时候也还有2个麻烦点:① 依赖 Node.js 环境 ② 关键的秘钥存储在本地文件中
本次迭代就是把这2个麻烦点解决掉!
生成原理
又拍云
参考文档:token 认证生成
简化成 JS 代码如下
// 基本配置
const operator = '账号'
const password = '密码'
const method = 'PUT' // 上传时用到的请求方法
const urlPrefix = 'bucketName/sourcePrefix' // 资源在OSS上的桶名称和公共路径前缀
const expire = Math.floor(Date.now() / 1000) + 3600 // 过期时间 1小时后过期
// 计算token
const token = base64(hmacSha1(MD5(password), `${method}&${urlPrefix}&${expire}`))
// 最终上传用到的请求头
const Authorization = `UPYUN ${operator}:${token}`
依赖的算法
- base64:将数据转换为 ASCII 字符串的编码
- HMAC_SHA-1:基于 SHA-1 哈希算法的消息认证码,用于验证消息的完整性和真实性
- MD5:哈希函数,用于生成数据的数字指纹
七牛云
参考文档:上传凭证,URL安全的Base64编码
简化成 JS 代码如下
// 基本配置
const accessKey = 'ACCESS_KEY'
const secretKey = 'SECRET_KEY'
const bucket = 'BUCKET_NAME' // OSS 桶名称
const expires = Math.floor(Date.now() / 1000) + 3600 // 过期时间 1小时后过期
const encodedFlags = base64ToUrlSafe(base64(JSON.stringify({
scope: bucket,
deadline: expires,
})))
const encodedSign = base64ToUrlSafe(base64(hmacSha1(secretKey, encodedFlags)))
// 最终上传用到的令牌
const uploadToken = `${accessKey}:${encodedSign}:${encodedFlags}`
其中 base64ToUrlSafe 是 “URL安全的Base64编码” 相关的方法
URL安全的Base64编码适用于以URL方式传递Base64编码结果的场景。该编码方式的基本过程是先将内容以Base64格式编码为字符串,然后检查该结果字符串,将字符串中的加号
+换成中划线-,并且将斜杠/换成下划线_。
// 实现如下
function base64ToUrlSafe(v: string) {
return v.replace(/\//g, '_').replace(/\+/g, '-')
}
其它依赖算法和又拍云基本一致 hmacSha1 和 base64。
加密方法的实现
这里分别介绍浏览器和 Node.js 环境下的简单实现。
前端浏览器侧实现
base64 和 HMAC_SHA-1 算法都有现成的实现,分别可以使用浏览器提供的 btoa 和 Crypto API。
function base64(value: string) {
return btoa(value)
}
HMAC_SHA-1
在阅读 MDN: Crypto API 文档时先可以看到 Crypto.subtle 的描述。
从字面意思不难看出就是我们需要的API。
从 HMAC 的例子中,就可以找到我们需要的关键信息:
关键代码如下
const encoder = new TextEncoder()
const encoded = encoder.encode(value)
const signature = await window.crypto.subtle.sign('HMAC', key, encoded)
其中 key 是我们需要的密钥,可以用 SubtleCrypto.importKey() 导入生成。
const encoder = new TextEncoder()
const key = await window.crypto.subtle.importKey(
'raw',
encoder.encode(password), // password 是我们的密钥
{ name: 'HMAC', hash: { name: 'SHA-1' } },
false,
['sign'],
)
最终我们的方法实现如下。
async function hmacSha1(key: string, value: string) {
const encoder = new TextEncoder()
const cryptoKey = await window.crypto.subtle.importKey(
'raw',
encoder.encode(key),
{ name: 'HMAC', hash: { name: 'SHA-1' } },
false,
['sign'],
)
const data = encoder.encode(value)
const hashBuffer = await window.crypto.subtle.sign('HMAC', cryptoKey, data)
return arrayBufferToBase64(hashBuffer) // 返回 base64 格式的结果
}
function arrayBufferToBase64(buffer: ArrayBuffer) {
const uint8Array = new Uint8Array(buffer)
const base64String = String.fromCharCode(...uint8Array)
return btoa(base64String)
}
MD5
MD5 可以使用 开源库 spark-md5
import SparkMD5 from 'spark-md5'
export function MD5(str: string): string {
return SparkMD5.hash(str)
}
Node.js 实现
Node.js 环境下,可以直接使用内置 node:crypto 模块提供的各种加密算法,十分方便。
HMAC_SHA-1
import crypto from 'crypto'
function hmacSha1(key: string, value: string) {
const hmac = crypto.createHmac('sha1', key)
hmac.update(value) // 设置用于计算校验值的字符串
return hmac.digest('base64') // 计算校验值,并按照 base64 返回
}
MD5
import crypto from 'crypto'
function MD5(value: string) {
const md5 = crypto.createHash('md5')
md5.update(value) // 设置用于计算 MD5 值的字符串
return md5.digest('hex') // 计算 MD5 值,并直接以十六进制字符串返回
}
安全问题
针对存储 账号&密码 等敏感信息的可以使用浏览器提供的账号密码管理能力存储。
例如 Chrome 中提供的 PasswordCredential 相关API。
调用后就可以唤起存储的弹窗。
最后
总结一下:浏览器中也可以使用window.crypto提供的 API,完成常用的加密算法调用,同时也可以在 Web Worker 中使用,可以有效提升性能。
当前这一版图床,应该也还不是最终版,后续计划将部分管理功能以某种可能得形式完成纯静态的支持。
欢迎评论区交流想法&意见
浏览器中生成 OSS 令牌 | Web Crypto API的更多相关文章
- 内卷时代下的前端技术-使用JavaScript在浏览器中生成PDF文档
背景 在计量领域中,计量检定是一种重要形式,主要用于评定计量器具的计量性能,确定其量值是否准确一致,实现手段包括计量检验.出具检定证书和加封盖印等. 在检定证书这一环节,存在一个难点,就是无法在线预览 ...
- 关于点击ztree的节点将页面生成到easyui的新增选项卡(easyui-tabs)时,总是在浏览器中生成一个新的页面的问题
最近的项目中用到了easyui,还有ztree菜单.在这里将我遇到的一些问题写出来算是做个笔记吧. 这是我头一次在博客园里分享代码,我的处女作,写的不好的地方还望各位见谅! 由于很久没有写过前台的东西 ...
- python中生成JWK(json web token)
#需要安装pyjwt import jwt import time # 使用 sanic 作为restful api 框架 def create_token(request): grant_type ...
- VS2010中生成遇到的 web.config 问题
1. 错误:无法在此路径使用此配置节.当站点管理员使用继承的配置文件中的 <location allowOverride="false"> 锁定对此节的访问时会出现 ...
- Web Animations API (JS动画利器)
原文地址:→传送门 写在前面 之前学习了CSS animation/setTimeout/setInterval/requestAnimationFrame等,这些都可以用在某种场景下的小动画,也可以 ...
- Web Storage API的介绍和使用
目录 简介 浏览器的本地存储技术 Web Storage相关接口 浏览器兼容性 隐身模式 使用Web Storage API 总结 简介 Web Storage为浏览器提供了方便的key value存 ...
- ASP.NET Core Web API中带有刷新令牌的JWT身份验证流程
ASP.NET Core Web API中带有刷新令牌的JWT身份验证流程 翻译自:地址 在今年年初,我整理了有关将JWT身份验证与ASP.NET Core Web API和Angular一起使用的详 ...
- 第十一章:WEB浏览器中的javascript
客户端javascript涵盖在本系列的第二部分第10章,主要讲解javascript是如何在web浏览器中实现的,这些章节介绍了大量的脚本宿主对象,这些对象可以表示浏览器窗口.文档树的内容.这些章节 ...
- JavaScript权威指南--WEB浏览器中的javascript
知识要点 1.客户端javascript window对象是所有客户端javascript特性和API的主要接入点.它表示web浏览器的一个窗口或窗体,并且可以用window表示来引用它.window ...
- HTML5 Web Speech API 结合Ext实现浏览器语音识别以及输入
简介 Web Speech API是HTML5技术中的一个提供原生语音识别技术的API,Google Chrome在25版之后开始支持Web Speech API,Google也提供了一个 ...
随机推荐
- .NET 中高效 Excel 解决方案 MiniExcel
前言 MiniExcel 是一个用于 .NET 平台的轻量级.高性能的库,专注于提供简单易用的 API 来处理 Excel 文件.以下是 MiniExcel 的特点总结: 轻量级与高效:MiniExc ...
- Superviso可视化监控进程
如果您需要同时运行多个 ThinkPHP 命令,可以在 Supervisor 中为每个命令创建一个单独的程序段.以下是示例配置,其中包含两个 ThinkPHP 命令:command1.php 和 co ...
- 【工具】SpringBoot项目如何查看某个maven依赖是否存在以及依赖链路
当我在SpringBoot项目中想加个依赖,但是不确定现有依赖的依赖的依赖.....有没有添加过这个依赖,怎么办呢?如果添加过了但是不知道我需要的这个依赖属于哪个依赖的下面,怎么查呢? IDEA中提供 ...
- 5/15课下作业:评价一下steam软件
用户界面: 登录后会弹出特惠广告,广告内容可能不常用.主界面简洁方便,启动游戏,购买游戏,浏览社区,浏览自己内容一目了然 记住用户选择: 登录一次后会记住用户的账户密码,可以直接进行用户间的切换,会记 ...
- 【Java】Generic 泛型
Generic 泛型 为什么需要泛型? 集合容器再设计阶段/声明阶段不能确定这个容器实际存储的是什么类型的对象 JDK5 以前只能把元素设计为Object基类 在JDK5之后用泛型来约束对象类型 除了 ...
- 【Spring】05 注解开发
环境搭建 配置ApplicationContext.xml容器文件[半注解实现] <?xml version="1.0" encoding="UTF-8" ...
- 【Tutorial C】01 概述
历史 History 欢迎来到C语言的世界!C语言是一种强大的专业化编程语言,深受业余和专业编程人员的欢迎. 在学习之前先让我们了解和认识它! C语言的原型是A语言(ALGOL 60语言). 1963 ...
- 人形机器人专用操作系统 —— KaihongOS还是ROS
机器人不是一个新词汇,机器人在人们生产生活中已经出现了几十年了,而最近最火的词汇是"智能机器人"或者是"人形机器人(humanoid)",而这二者之间的区别就是 ...
- Cannot lower pallas_call on platform: cuda
Jax框架JAX-Triton不可用: 参考地址: MLIR translation rule for primitive 'pallas_call' not found for platform c ...
- Java IO 流详解
概述 流是一个抽象的概念,代表了数据的无结构化传递.流的本质是数据在不同设备之间的传输.在 Java 中,数据的读取和写入都是以流的方式进行的 在 Java 中,根据数据流向的不同,可以将流分为输入( ...