cccb7cfc
tangwang
init
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
后端OAuth2.0认证流程
1. 安装依赖
Codeblock
1
npm install express crypto axios
2. 配置⽂件/config/index.js
⽤于存放APP_NAME,CLIENT_ID,CLIENT_SECRET,REDIRECT_URI
Codeblock
const CLIENT_ID = "<YOUR_CLIENT_ID>";
const CLIENT_SECRET = "<YOUR_CLIENT_SECRET>";
const BASE_URL = "<BASE_URL>";
const REDIRECT_URI = `${BASE_URL}/auth/shoplazza/callback`;
let access_token = {};
3. 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" };
}
};
4. 认证路由/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;
5. 启动服务器挂载oauth,认证路由
Codeblock
1
2
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
3
4
console.log(`Server running on http://localhost:${PORT}`);
});
|