后端OAuth2.0认证流程
- 安装依赖
Codeblock
1
npm install express crypto axios
- 配置⽂件/config/index.js ⽤于存放APP_NAME,CLIENT_ID,CLIENT_SECRET,REDIRECT_URI Codeblock
const CLIENT_ID = "";
const CLIENT_SECRET = "";
const BASE_URL = "";
const REDIRECT_URI = ${BASE_URL}/auth/shoplazza/callback;
let access_token = {};
- HMAC校验中间件/middleware/hmacValidator.js Codeblock
9 import crypto from "crypto"; export const hmacValidator = async (ctx, next) => { const { hmac, ...queryParams } = ctx.query; if (!hmac) { ctx.status = 400; ctx.body = { error: "Missing HMAC parameter" }; return;
} // 计算 HMAC 校验
const message = Object.keys(queryParams)
.sort()
.map((key) => ${key}=${queryParams[key]})
.join("&");
const generatedHmac = crypto
.createHmac("sha256", process.env.CLIENT_SECRET)
.update(message)
.digest("hex");
if (crypto.timingSafeEqual(Buffer.from(generatedHmac), Buffer.from(hmac))) {
await next();
} else {
ctx.status = 403;
ctx.body = { error: "HMAC validation failed" };
}
};
- 认证路由/routes/auth.js Codeblock
import Router from "koa-router";
import crypto from "crypto";
import axios from "axios";
import { APP_NAME, CLIENT_ID, CLIENT_SECRET, REDIRECT_URI } from
"../config/index.js";
import { hmacValidator } from "../middleware/hmacValidator.js";
const router = new Router({ prefix: "/api" });
router.get(/auth/install, async (ctx) => {
const shop = ctx.query.shop;
if (!shop) {
ctx.status = 400;
ctx.body = { error: "Missing shop parameter" };
return;
}
const scopes = "read_customer,read_product,write_product";
const state = crypto.randomBytes(16).toString("hex");
const redirectUri = https://${ctx.host}${REDIRECT_URI};
const authUrl = https://${shop}/admin/oauth/authorize?
client_id=${CLIENT_ID}&scope=${scopes}&redirect_uri=${redirectUri}&response_typ
e=code&state=${state};
ctx.redirect(authUrl);
});
// ** Step 2:
处理
OAuth
回调
**
router.get(/auth/callback, hmacValidator, async (ctx) => {
const { code, shop } = ctx.query;
if (!shop || !code) {
ctx.status = 400;
ctx.body = { error: "Missing required parameters" };
return;
}
const redirectUri = https://${ctx.host}${REDIRECT_URI};
try {
const response = await axios.post(https://${shop}/admin/oauth/token, {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code,
grant_type: "authorization_code",
redirect_uri: redirectUri,
});
console.log("
获取
access_token
成功
:", response.data);
ctx.body = response.data; //
返回
token
及
store
信息
} catch (error) { console.error(" 获取 access_token 失败 :", error.message); ctx.status = 500; ctx.body = { error: "Failed to obtain access token" }; } }); export default router;
- 启动服务器挂载oauth,认证路由
Codeblock
1
2
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
3
4
console.log(
Server running on http://localhost:${PORT}); });