后端OAuth2.0认证流程.md 2.96 KB

后端OAuth2.0认证流程

  1. 安装依赖 Codeblock 1 npm install express crypto axios
    1. 配置⽂件/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 = {};

  1. 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" }; } };

  1. 认证路由/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;

  1. 启动服务器挂载oauth,认证路由 Codeblock 1 2 const PORT = process.env.PORT || 3000; app.listen(PORT, () => { 3 4 console.log(Server running on http://localhost:${PORT}); });