Blame view

old/后端OAuth2.0认证流程.md 2.96 KB
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}`);
   });