返回 AiToEarn
google.service.ts
根目录 / project / aitoearn-electron / server / src / modules / plat / google / google.service.ts
1 /*
2 * @Author: zhangwei
3 * @Date: 2025-05-15 20:59:55
4 * @LastEditTime: 2025-04-27 17:58:21
5 * @LastEditors: zhangwei
6 * @Description: youtube
7 */
8
9 import axios from 'axios';
10 import { v4 as uuidv4 } from 'uuid';
11 import { createHash, createHmac } from 'crypto';
12 import { AccessToken } from './comment';
13 import { URLSearchParams } from 'url';
14
15 import { RedisService } from 'src/lib/redis/redis.service';
16 import { getCurrentTimestamp } from 'src/util/time.util';
17 import { getRandomString } from 'src/util';
18 import { AuthService } from 'src/auth/auth.service';
19 import { InjectModel } from '@nestjs/mongoose';
20 import { Model } from 'mongoose';
21 import { User, UserStatus } from 'src/db/schema/user.schema';
22 import { Injectable, Inject, forwardRef } from '@nestjs/common';
23 import { ConfigService } from '@nestjs/config';
24
25 const fs = require('fs');
26 const readline = require('readline');
27 const { google } = require('googleapis');
28 // const OAuth2 = google.auth.OAuth2;
29
30 @Injectable()
31 export class GoogleService {
32 private oauth2Client: any;
33 private webClientSecret: string;
34 private webClientId: string;
35 private webRenderBaseUrl: string;
36
37 constructor(
38 private configService: ConfigService,
39 @InjectModel(User.name) // 注入 User 模型
40 private userModel: Model<User>,
41
42 private readonly redisService: RedisService,
43 @Inject(forwardRef(() => AuthService))
44 private readonly AuthService: AuthService,
45
46 ) {
47 this.oauth2Client = new google.auth.OAuth2();
48 this.initGoogleSecrets();
49 }
50
51 /**
52 * 初始化 OAuth2 客户端并设置凭证
53 * @param accessToken 传入的 access_token
54 */
55 setCredentials(accessToken: string) {
56 this.oauth2Client.setCredentials({
57 access_token: accessToken,
58 });
59 }
60
61 /**
62 * 获取初始化好的 OAuth2 客户端
63 * @returns 返回 OAuth2 客户端
64 */
65 getClient() {
66 return this.oauth2Client;
67 }
68
69 async initGoogleSecrets() {
70 this.webClientSecret = this.configService.get<string>("GOOGLE_CONFIG.WEB_CLIENT_SECRET");
71 this.webClientId = this.configService.get<string>("GOOGLE_CONFIG.WEB_CLIENT_ID");
72 this.webRenderBaseUrl = this.configService.get<string>("GOOGLE_CONFIG.WEB_RENDER_URL");
73 }
74
75 async getAuthCode(mail: string, platform: string, type: string) {
76 try {
77 // const { tokens } = await this.oauth2Client.getToken(code);
78 // this.oauth2Client.setCredentials(tokens);
79 // this.oauth2Client.credentials = tokens;
80
81
82 const state = getRandomString(8);
83 this.redisService.setKey(`google:state:${state}`, { mail }, 60 * 10);
84
85 // 根据参数platform选择 平台的权限
86 let platScope = "";
87 const platformScopes = {
88 google: [
89 "openid",
90 "email",
91 "https://www.googleapis.com/auth/calendar.readonly",
92 "https://www.googleapis.com/auth/userinfo.profile",
93 "https://www.googleapis.com/auth/youtube.force-ssl",
94 "https://www.googleapis.com/auth/youtube.readonly",
95 "https://www.googleapis.com/auth/youtube.upload",
96 "https://www.googleapis.com/auth/userinfo.profile"
97 ],
98 youtube: [
99 "https://www.googleapis.com/auth/youtube.force-ssl",
100 "https://www.googleapis.com/auth/youtube.readonly",
101 "https://www.googleapis.com/auth/youtube.upload",
102 "https://www.googleapis.com/auth/userinfo.profile"
103 ],
104 meta: [
105 "https://www.googleapis.com/auth/meta",
106 "https://www.googleapis.com/auth/userinfo.profile"
107 ]
108 };
109
110 if (platform === "google") {
111 platScope += "" + platformScopes.google.join(" ");
112 } else if (platformScopes.hasOwnProperty(platform)) {
113 platScope += " " + platformScopes[platform].join(" ");
114 }
115
116
117 const params = new URLSearchParams({
118 // scope: "openid email https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload",
119 // scope: "openid https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload",
120 scope: platScope,
121 access_type: "offline",
122 include_granted_scopes: "true",
123 response_type: "code",
124 state: state,
125 redirect_uri: `${this.webRenderBaseUrl}/api/plat/${platform}/auth/callback`,
126 client_id: this.webClientId,
127 // prompt: "none", // 默认 consent
128 prompt: "consent" // 强制重新授权
129 // login_hint: mail,
130 });
131 // const authUrl = `https://accounts.google.com/o/oauth2/v2/auth`;
132 const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
133
134 // const result = await axios.post<{
135 // code: number; // 0;
136 // message: string; // '0';
137 // ttl: number; // 1;
138 // request_id: string; // '7b753a287405461f5afa526a1f672094';
139 // data: {
140 // upload_token: string; // 'd30bedaa4d8eb3128cf35ddc1030e27d';
141 // };
142 // }>(url, body.toString(), {
143 // headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
144 // // headers: { 'Content-Type': 'application/json' }
145 // });
146 // // return result.data.data.upload_token;
147
148 // return result.data;
149
150 authUrl.search = params.toString();
151
152 return authUrl.toString(); // 返回生成的 URL
153
154 } catch (err) {
155 console.log('Error while trying to retrieve access token', err);
156 return err;
157 };
158 }
159
160
161 async getAuthCode_v2(platform: string, type: string) {
162 try {
163 const state = getRandomString(8);
164 // this.redisService.setKey(`google:state:${state}`, { mail }, 60 * 10);
165
166 console.log("++++++++++++++++++++++++")
167 console.log(this.webClientId);
168 console.log("++++++++++++++++++++++++")
169 // 根据参数platform选择 平台的权限
170 let platScope = "";
171 const platformScopes = {
172 google: [
173 "openid",
174 "email",
175 "https://www.googleapis.com/auth/calendar.readonly",
176 "https://www.googleapis.com/auth/userinfo.profile",
177 "https://www.googleapis.com/auth/youtube.force-ssl",
178 "https://www.googleapis.com/auth/youtube.readonly",
179 "https://www.googleapis.com/auth/youtube.upload",
180 "https://www.googleapis.com/auth/userinfo.profile"
181 ],
182 youtube: [
183 "https://www.googleapis.com/auth/youtube.force-ssl",
184 "https://www.googleapis.com/auth/youtube.readonly",
185 "https://www.googleapis.com/auth/youtube.upload",
186 "https://www.googleapis.com/auth/userinfo.profile"
187 ],
188 meta: [
189 "https://www.googleapis.com/auth/meta",
190 "https://www.googleapis.com/auth/userinfo.profile"
191 ]
192 };
193
194 if (platform === "google") {
195 platScope += "" + platformScopes.google.join(" ");
196 } else if (platformScopes.hasOwnProperty(platform)) {
197 platScope += " " + platformScopes[platform].join(" ");
198 }
199
200 const params = new URLSearchParams({
201 // scope: "openid email https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload",
202 // scope: "openid https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload",
203 scope: platScope,
204 access_type: "offline",
205 include_granted_scopes: "true",
206 response_type: "code",
207 state: state,
208 redirect_uri: `${this.webRenderBaseUrl}/api/plat/google/auth/accessToken`,
209 client_id: this.webClientId,
210 // prompt: "none", // 默认 consent
211 // prompt: "consent"
212 // login_hint: mail,
213 });
214 // const authUrl = `https://accounts.google.com/o/oauth2/v2/auth`;
215 const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
216
217 // const result = await axios.post<{
218 // code: number; // 0;
219 // message: string; // '0';
220 // ttl: number; // 1;
221 // request_id: string; // '7b753a287405461f5afa526a1f672094';
222 // data: {
223 // upload_token: string; // 'd30bedaa4d8eb3128cf35ddc1030e27d';
224 // };
225 // }>(url, body.toString(), {
226 // headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
227 // // headers: { 'Content-Type': 'application/json' }
228 // });
229 // // return result.data.data.upload_token;
230
231 // return result.data;
232
233 authUrl.search = params.toString();
234
235 return authUrl.toString(); // 返回生成的 URL
236
237 } catch (err) {
238 console.log('Error while trying to retrieve access token', err);
239 return err;
240 };
241 }
242
243
244 /**
245 * 获取授权Token
246 * @param code
247 * @returns
248 */
249 async setUserAccessToken(data: {
250 code: string;
251 state: string;
252 }) {
253
254 const { code, state } = data;
255 console.log("================ code state=======================")
256 console.log(code, state);
257 console.log("=============================================")
258
259 try {
260 const params = new URLSearchParams({
261 code: code,
262 redirect_uri: `${this.webRenderBaseUrl}/api/plat/google/auth/accessToken`,
263 client_id: this.webClientId,
264 grant_type: "authorization_code",
265 client_secret: this.webClientSecret,
266 });
267 const tokenUrl = `https://oauth2.googleapis.com/token`;
268
269 const result = await axios.post<{
270 access_token: string;
271 expires_in: number;
272 token_type: string;
273 refresh_token: string;
274 id_token: string;
275 }>(tokenUrl , params.toString(), {
276 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
277 });
278
279 const mailInfo = await this.redisService.get(`google:state:${state}`);
280 // console.log("----------------");
281 // console.log(result.data);
282 // console.log("mail:", mailInfo);
283 const accessTokenInfo = result.data;
284
285 // 初始化 OAuth2 客户端
286 // const oAuth2Client = new google.auth.OAuth2();
287 this.oauth2Client.setCredentials({
288 access_token: accessTokenInfo.access_token,
289 });
290
291 const idToken = accessTokenInfo.id_token;
292 const ticket = await this.oauth2Client.verifyIdToken({ idToken, audience: this.webClientId });
293 const googleUser = ticket.getPayload();
294 const googleAccount = { // Google 唯一 ID
295 googleId: googleUser.sub,
296 email: googleUser.email,
297 accessToken: result.data.access_token,
298 refreshToken: result.data.refresh_token,
299 expiresAt: getCurrentTimestamp() + result.data.expires_in
300 };
301
302 let userInfo: User | null = null;
303 // 优先用 Google ID 查找(最准确)
304 if (googleUser.sub) {
305 userInfo = await this.userModel.findOne({
306 'googleAccount.googleId': googleUser.sub,
307 status: UserStatus.OPEN,
308 });
309 }
310 // console.log("这里的info:", userInfo, googleUser.sub, googleUser.email)
311 // 如果没有找到,再用 email 兜底查找(存在被别人注册的风险,需谨慎)
312 if (!userInfo && googleUser.email) {
313 userInfo = await this.userModel.findOne({
314 mail: googleUser.email,
315 status: UserStatus.OPEN,
316 });
317 }
318 console.log("这里的info2222:", userInfo, googleUser.email)
319
320 if (userInfo) {
321 // 绑定 Google 信息
322 // userInfo.googleId = googleId;
323 // userInfo.mail = mailInfo.mail;
324 userInfo.googleAccount = googleAccount
325 // if(userInfo.googleAccount.googleId=== googleAccount.googleId) {
326 // userInfo.googleAccount = googleAccount; // 覆盖旧 token
327 // } else {
328 // userInfo.googleAccount.push(googleAccount); // 添加新 Google 帐号
329 // }
330
331 console.log("更新后的数据:--", userInfo.googleAccount, userInfo.id)
332 await this.userModel.updateOne(
333 { _id: Object(userInfo.id) },
334 { $set: { googleAccount: userInfo.googleAccount } },
335 );
336
337 // return userInfo;
338 } else {
339 console.log("用户不存在,创建");
340 const newData = {
341 name: `用户_${getRandomString(8)}`,
342 mail: mailInfo.mail,
343 googleAccount: googleAccount,
344 status: UserStatus.OPEN,
345 };
346
347 userInfo = await this.userModel.create(newData);
348 // console.log("新创建的用户:", userInfo);
349 }
350 console.log("userInfo22222:---", userInfo);
351 const userId = userInfo.id
352
353 this.redisService.del(`UserInfo:${userInfo.id}`);
354
355 const TokenInfo = {
356 phone: userInfo.phone,
357 id: userInfo.id,
358 name: userInfo.name,
359 isManager: false,
360 googleId: userInfo.googleAccount.googleId
361 }
362 console.log("发送获取systemToken的info---", TokenInfo);
363 const systemToken = await this.AuthService.generateToken(TokenInfo)
364 // 剩余有效秒数
365 // const expires =
366 // accessTokenInfo.expires_in - getCurrentTimestamp() - 60 * 60;
367
368 // const expires = 30 * 24 * 60 * 60
369 console.log("accessTokenInfo:---", accessTokenInfo);
370 // console.log("expires:---", accessTokenInfo.expires_in);
371 this.redisService.setKey(
372 `google:accessToken:${userId}`,
373 accessTokenInfo,
374 accessTokenInfo.expires_in
375 );
376
377 // return result.data;
378 return systemToken;
379 } catch (err) {
380 console.log('Error while trying to retrieve access token', err);
381 return err;
382 };
383 }
384
385 /**
386 * Google登录
387 * @param clientId Google客户端ID
388 * @param credential Google认证凭证
389 * @returns Account
390 */
391 async googleLogin(clientId: string, credential: string): Promise<any> {
392 try {
393 console.log('Verifying Google token with:');
394 // 验证Google token
395 const ticket = await this.oauth2Client.verifyIdToken({
396 idToken: credential,
397 audience: clientId,
398 });
399 console.log('ticket',ticket)
400 const googleUser = ticket.getPayload();
401 console.log('payload',googleUser)
402 if (!googleUser) {
403 throw new Error('Invalid Google token');
404 }
405
406 console.log('Google login success, googleUser:', googleUser);
407
408 const googleAccount = {
409 googleId: googleUser.sub,
410 email: googleUser.email,
411 // accessToken: result.data.access_token,
412 refreshToken: null,
413 // expiresAt: result.data.expires_in
414 };
415
416 let userInfo: User | null = null;
417 // 优先用 Google ID 查找(最准确)
418 if (googleUser.sub) {
419 userInfo = await this.userModel.findOne({
420 'googleAccount.googleId': googleUser.sub,
421 status: UserStatus.OPEN,
422 });
423 }
424 // console.log("这里的info:", userInfo, googleUser.sub, googleUser.email)
425 // 如果没有找到,再用 email 兜底查找(存在被别人注册的风险,需谨慎)
426 if (!userInfo && googleUser.email) {
427 userInfo = await this.userModel.findOne({
428 mail: googleUser.email,
429 status: UserStatus.OPEN,
430 });
431 }
432 console.log("这里的info2222:", userInfo, googleUser.email)
433
434 if (userInfo) {
435 console.log("已有用户,更新绑定的 googleAccount:", userInfo);
436 // 绑定 Google 信息
437 // userInfo.googleId = googleId;
438 // userInfo.mail = mailInfo.mail;
439 // userInfo.googleAccount = googleAccount
440 // 合并逻辑:仅在新 refresh_token 存在时覆盖旧的
441 const updatedGoogleAccount = {
442 ...userInfo.googleAccount, // 原有内容
443 ...googleAccount, // 新数据覆盖(但不覆盖 refresh_token)
444 refreshToken: googleAccount.refreshToken != null && googleAccount.refreshToken !== ''
445 ? googleAccount.refreshToken
446 : userInfo.googleAccount?.refreshToken,
447 };
448
449 console.log("更新后的数据:--", updatedGoogleAccount, userInfo.id);
450
451 // console.log("更新后的数据:--", userInfo.googleAccount, userInfo.id)
452 // await this.userModel.updateOne(
453 // { _id: Object(userInfo.id) },
454 // { $set: { googleAccount: userInfo.googleAccount } },
455 // );
456 await this.userModel.updateOne(
457 { _id: Object(userInfo.id) },
458 { $set: { googleAccount: updatedGoogleAccount } },
459 );
460
461 // return userInfo;
462 } else {
463 console.log("用户不存在,创建");
464 const newData = {
465 name: `用户_${getRandomString(8)}`,
466 mail: googleUser.email,
467 googleAccount: googleAccount,
468 status: UserStatus.OPEN,
469 };
470
471 userInfo = await this.userModel.create(newData);
472 // console.log("新创建的用户:", userInfo);
473 }
474 console.log("userInfo22222:---", userInfo);
475 this.redisService.del(`UserInfo:${userInfo.id}`);
476
477 const TokenInfo = {
478 phone: userInfo.phone,
479 id: userInfo.id,
480 name: userInfo.name,
481 isManager: false,
482 createTime: userInfo.createTime,
483 mail: userInfo.mail,
484 status: userInfo.status,
485 updateTime: userInfo.updateTime,
486 googleAccount: userInfo.googleAccount
487 }
488 console.log("发送获取systemToken的info---", TokenInfo);
489 const systemToken = await this.AuthService.generateToken(TokenInfo)
490 // 剩余有效秒数
491 // const expires =
492 // accessTokenInfo.expires_in - getCurrentTimestamp() - 60 * 60;
493
494 // const expires = 30 * 24 * 60 * 60
495 // console.log("accessTokenInfo:---", accessTokenInfo);
496 // console.log("expires:---", accessTokenInfo.expires_in);
497 // this.redisService.setKey(
498 // `google:accessToken:${userId}`,
499 // accessTokenInfo,
500 // accessTokenInfo.expires_in
501 // );
502 const loginResult = {
503 token: null,
504 type: "login",
505 userInfo: TokenInfo
506 }
507 loginResult.token = systemToken
508 return loginResult;
509 } catch (error) {
510 console.error('Google login error:', error);
511 throw new Error(`Google login failed: ${error.message}`);
512 }
513 }
514
515 async setUserAccessToken_V2(data: {
516 code: string;
517 state: string;
518 }) {
519
520 const { code, state } = data;
521 console.log("================ code state=======================")
522 console.log(code, state);
523 console.log("=============================================")
524
525 try {
526 const params = new URLSearchParams({
527 code: code,
528 redirect_uri: `${this.webRenderBaseUrl}/api/plat/google/auth/accessToken`,
529 client_id: this.webClientId,
530 grant_type: "authorization_code",
531 client_secret: this.webClientSecret,
532 });
533 const tokenUrl = `https://oauth2.googleapis.com/token`;
534
535 const result = await axios.post<{
536 access_token: string;
537 expires_in: number;
538 token_type: string;
539 refresh_token: string;
540 id_token: string;
541 }>(tokenUrl , params.toString(), {
542 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
543 // headers: { 'Content-Type': 'application/json' }
544 });
545
546 // const mailInfo = await this.redisService.get(`google:state:${state}`);
547 console.log("----------------");
548 console.log(result.data);
549 // console.log("mail:", mailInfo);
550 const accessTokenInfo = result.data;
551
552 // 初始化 OAuth2 客户端
553 // const oAuth2Client = new google.auth.OAuth2();
554 this.oauth2Client.setCredentials({
555 access_token: accessTokenInfo.access_token,
556 });
557
558 const idToken = accessTokenInfo.id_token;
559 const ticket = await this.oauth2Client.verifyIdToken({ idToken, audience: this.webClientId });
560 const googleUser = ticket.getPayload();
561 console.log(googleUser);
562 // const googleId = googleUser.sub; // Google 唯一 ID
563 const googleAccount = {
564 googleId: googleUser.sub,
565 email: googleUser.email,
566 accessToken: result.data.access_token,
567 refreshToken: result.data.refresh_token,
568 expiresAt: getCurrentTimestamp() + result.data.expires_in
569 };
570
571 let userInfo: User | null = null;
572 // 优先用 Google ID 查找(最准确)
573 if (googleUser.sub) {
574 userInfo = await this.userModel.findOne({
575 'googleAccount.googleId': googleUser.sub,
576 status: UserStatus.OPEN,
577 });
578 }
579 // console.log("这里的info:", userInfo, googleUser.sub, googleUser.email)
580 // 如果没有找到,再用 email 兜底查找(存在被别人注册的风险,需谨慎)
581 if (!userInfo && googleUser.email) {
582 userInfo = await this.userModel.findOne({
583 mail: googleUser.email,
584 status: UserStatus.OPEN,
585 });
586 }
587 console.log("这里的info2222:", userInfo, googleUser.email)
588
589 if (userInfo) {
590 console.log("已有用户,更新绑定的 googleAccount:", userInfo);
591 // 绑定 Google 信息
592 // userInfo.googleId = googleId;
593 // userInfo.mail = mailInfo.mail;
594 // userInfo.googleAccount = googleAccount
595 // 合并逻辑:仅在新 refresh_token 存在时覆盖旧的
596 const updatedGoogleAccount = {
597 ...userInfo.googleAccount, // 原有内容
598 ...googleAccount, // 新数据覆盖(但不覆盖 refresh_token)
599 refreshToken: googleAccount.refreshToken != null && googleAccount.refreshToken !== ''
600 ? googleAccount.refreshToken
601 : userInfo.googleAccount?.refreshToken,
602 };
603
604 console.log("更新后的数据:--", updatedGoogleAccount, userInfo.id);
605
606 // console.log("更新后的数据:--", userInfo.googleAccount, userInfo.id)
607 // await this.userModel.updateOne(
608 // { _id: Object(userInfo.id) },
609 // { $set: { googleAccount: userInfo.googleAccount } },
610 // );
611 await this.userModel.updateOne(
612 { _id: Object(userInfo.id) },
613 { $set: { googleAccount: updatedGoogleAccount } },
614 );
615
616 // return userInfo;
617 } else {
618 console.log("用户不存在,创建");
619 const newData = {
620 name: `用户_${getRandomString(8)}`,
621 mail: googleUser.email,
622 googleAccount: googleAccount,
623 status: UserStatus.OPEN,
624 };
625
626 userInfo = await this.userModel.create(newData);
627 // console.log("新创建的用户:", userInfo);
628 }
629 console.log("userInfo22222:---", userInfo);
630 const userId = userInfo.id
631
632 this.redisService.del(`UserInfo:${userInfo.id}`);
633
634 const TokenInfo = {
635 phone: userInfo.phone,
636 id: userInfo.id,
637 name: userInfo.name,
638 isManager: false,
639 googleId: userInfo.googleAccount.googleId,
640 mail: userInfo.mail
641 }
642 console.log("发送获取systemToken的info---", TokenInfo);
643 const systemToken = await this.AuthService.generateToken(TokenInfo)
644 // 剩余有效秒数
645 // const expires =
646 // accessTokenInfo.expires_in - getCurrentTimestamp() - 60 * 60;
647
648 // const expires = 30 * 24 * 60 * 60
649 console.log("accessTokenInfo:---", accessTokenInfo);
650 // console.log("expires:---", accessTokenInfo.expires_in);
651 this.redisService.setKey(
652 `google:accessToken:${userId}`,
653 accessTokenInfo,
654 accessTokenInfo.expires_in
655 );
656
657 const loginResult = {
658 token: null,
659 type: "login",
660 userInfo: TokenInfo
661 }
662 loginResult.token = systemToken
663 return loginResult;
664
665 // return result.data;
666 // return systemToken;
667 } catch (err) {
668 console.log('Error while trying to retrieve access token', err);
669 return err;
670 };
671 }
672
673 async getUserAccessToken(userId: string): Promise<string> {
674 const res: AccessToken = await this.redisService.get(
675 `google:accessToken:${userId}`,
676 );
677 // if (!res) return '';
678
679 // // 剩余时间
680 // const overTime = res.expires_in;
681
682 // if (overTime < 60 * 60 && overTime > 0) {
683 // // 刷新token
684 // this.refreshAccessToken(userId, res.refresh_token);
685 // }
686 const userInfo = await this.userModel.findOne({_id: userId});
687 this.refreshAccessToken(userId, userInfo.googleAccount.refreshToken);
688 return res.access_token;
689 }
690
691 /**
692 * 刷新授权Token
693 * @param refreshToken
694 * @returns
695 */
696 async refreshAccessToken(userId: string, refreshToken?: string) {
697 try {
698 const userInfo = await this.userModel.findOne({_id: userId});
699 if(!refreshToken) {
700
701 console.log("=============userInfo====================");
702 console.log(userInfo)
703 refreshToken = userInfo?.googleAccount?.refreshToken ?? ''
704 }
705
706 const tokenUrl = 'https://oauth2.googleapis.com/token';
707
708 // 请求体的参数
709 const params = new URLSearchParams({
710 client_id: this.webClientId, // 使用你的 client_id
711 client_secret: this.webClientSecret, // 使用你的 client_secret
712 refresh_token: refreshToken, // 提供刷新令牌
713 grant_type: 'refresh_token', // 认证类型是刷新令牌
714 });
715
716 // 发送 POST 请求到 Google token endpoint 来刷新 access token
717 const response = await axios.post(tokenUrl, params.toString(), {
718 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
719 });
720 console.log("================response================")
721 console.log(response);
722 const accessTokenInfo = response.data;
723 // console.log("================accessTokenInfo================")
724 // console.log(accessTokenInfo);
725 // 剩余有效秒数
726 const expires = accessTokenInfo.expires_in
727 // accessTokenInfo.expires_in - getCurrentTimestamp() - 60 * 60;
728 this.redisService.setKey(
729 `google:accessToken:${userId}`,
730 accessTokenInfo,
731 expires,
732 );
733
734
735 const TokenInfo = {
736 phone: userInfo?.phone ?? '', // 如果 userInfo.phone 为 undefined 或 null,则使用空字符串
737 id: userId,
738 name: userInfo.name,
739 isManager: false,
740 googleId: userInfo?.googleAccount?.googleId ?? ''
741 }
742 console.log("发送获取systemToken的info---", TokenInfo);
743 const systemToken = await this.AuthService.generateToken(TokenInfo)
744 // 剩余有效秒数
745 // const expires =
746 // accessTokenInfo.expires_in - getCurrentTimestamp() - 60 * 60;
747
748 // const expires = 30 * 24 * 60 * 60
749 console.log("accessTokenInfo:---", accessTokenInfo);
750 // console.log("expires:---", accessTokenInfo.expires_in);
751 this.redisService.setKey(
752 `google:accessToken:${userId}`,
753 accessTokenInfo,
754 accessTokenInfo.expires_in
755 );
756
757 // return result.data;
758 return systemToken;
759
760
761 // 返回新的 access token 和其他信息
762 // return response.data; // 包含新的 access_token、expires_in、token_type 等信息
763 } catch (err) {
764 console.log('Error while refreshing access token', err);
765 throw new Error('Failed to refresh access token');
766 }
767 }
768
769 /**
770 * 查询用户已授权权限列表
771 * @returns
772 */
773 async getAccountScopes(accessToken: string) {
774 try {
775 // 初始化 OAuth2 客户端
776 // const oAuth2Client = new google.auth.OAuth2();
777 this.oauth2Client.setCredentials({
778 access_token: accessToken,
779 });
780
781 // 通过访问 token 查询 token 信息
782 const tokenInfo = await google.oauth2('v2').tokeninfo({
783 access_token: accessToken,
784 });
785
786 console.log('Token Info:', tokenInfo.data);
787
788 // 查询用户的基本信息
789 const userInfo = await google.oauth2('v2').userinfo.get({
790 auth: this.oauth2Client,
791 });
792
793 console.log('User Info:', userInfo.data);
794
795 // 返回用户的权限和信息
796 return {
797 tokenInfo: tokenInfo.data,
798 userInfo: userInfo.data,
799 };
800 } catch (error) {
801 console.error('Error getting user permissions:', error);
802 throw new Error('Failed to get user permissions');
803 }
804 }
805
806 /**
807 * 获取已授权的用户信息
808 * @param data
809 */
810 async getUserInfo(accessToken: string, token) {
811 try {
812 const response = await axios.get('https://www.googleapis.com/oauth2/v3/userinfo', {
813 headers: {
814 Authorization: `Bearer ${accessToken}`,
815 },
816 });
817
818 // 返回用户信息
819 return response.data;
820 } catch (err) {
821 console.error('Error fetching user info:', err);
822 throw new Error('Failed to fetch user info');
823 }
824 }
825
826 }
827
828
829
829 lines TYPESCRIPT