【问题标题】:Is credentials.json necessary to use Google gmail api?使用 Google gmail api 是否需要 credentials.json?
【发布时间】:2021-03-31 23:07:04
【问题描述】:

在 node.js 中,我想通过 google api 发送 gmail。但只有使用 credentials.json 的示例。

Credentials.json 好像很难推送 github,很难做 env,也很难使用 github action secret。

有没有什么方法可以在没有 credentials.json 的情况下调用 gmail api ??? 如果没有办法,我该如何管理credentials.json??

【问题讨论】:

    标签: node.js google-api google-oauth gmail-api google-developers-console


    【解决方案1】:

    要使用 Google API,您必须首先在 Google 开发者控制台上创建一个项目。创建项目后,您将能够启用要在项目中使用的 api。

    为了访问任何数据,您需要创建凭据。这些凭据向 Google 识别您的项目,并由您的应用程序用于授权和验证用户 vai Oauth2。

    如果您的项目中没有 credeitnals.json 文件,则无法使用任何 google api 访问私人用户数据。

    【讨论】:

    • 所以如果没有办法,我该如何管理credentials.json?由于安全原因,我们不能将 credentials.json 放在项目中并将其推送到 github
    • 我尝试不使用 credentials.json,但将该文件的内容作为 env 提供。因此,您不需要为部署提供任何文件。请在下面查看。
    • 共享您的凭据Can I really not ship open source with Client ID? 违反 TOS,而是指导您的用户如何创建自己的凭据,以便他们能够使用您的代码。
    【解决方案2】:

    在 nodejs 中,我编写了如下代码。

    您需要以其他方式(例如环境)提供 clientId、clientSecret、refreshToken、redirectUrl,而不是 exclude credentials.json

    export class GmailService {
      TOKEN_PATH: string = 'token.json';
      SCOPES: string[] = ['https://www.googleapis.com/auth/gmail.send'];
      refreshTokenUrl: string = 'https://oauth2.googleapis.com/token';
      ACCESS_TYPE: string = 'offline';
      oAuth2Client: any;
      gmailClient: gmail_v1.Gmail;
    
      constructor(private readonly configService: ConfigService) {
        this.oAuth2Client = new google.auth.OAuth2(
          this.configService.get(env.mailer.clientId),
          this.configService.get(env.mailer.clientSecret),
          this.configService.get(env.mailer.redirectUrl),
        );
        this.gmailClient = gmail({ version: 'v1', auth: this.oAuth2Client });
        this.authorize().catch((err: Error) => {
          throw err;
        });
      }
    
      private static encodeMessage(msg: Buffer): string {
        return Buffer.from(msg)
          .toString('base64')
          .replace(/\+/g, '-')
          .replace(/\//g, '_')
          .replace(/=+&/g, '');
      }
    
      async sendMail(mail: Mail.Options): Promise<void> {
        if (this.configService.get(env.environment) === 'test') return;
        if (this.configService.get(env.environment) !== 'production') {
          mail.to = this.configService.get(env.mailer.testTarget);
        }
        await this.authorize();
        await this.send(mail);
      }
    
      async authorize(): Promise<void> {
        // check token file exists
        await fs.readFile(this.TOKEN_PATH, async (err: Error, tokenFile: any) => {
          let token: Token;
          if (err) {
            token = await this.getNewToken(); // token file not exist
          } else {
            token = JSON.parse(tokenFile);
            if (token.expiry_date - new Date().getTime() < 30000) {
              token = await this.getNewToken(); // token was expired
            }
          }
          this.oAuth2Client.setCredentials(token);
        });
      }
    
      // refresh token
      async getNewToken(): Promise<Token> {
        const response: AxiosResponse = await axios.post(this.refreshTokenUrl, {
          client_id: this.configService.get(env.mailer.clientId),
          client_secret: this.configService.get(env.mailer.clientSecret),
          grant_type: 'refresh_token',
          refresh_token: this.configService.get(env.mailer.refreshToken),
        });
        const token: Token = response.data;
        if (token.expires_in && !token.expiry_date) {
          token.expiry_date = new Date().getTime() + token.expires_in * 1000;
        }
        await fs.writeFile(this.TOKEN_PATH, JSON.stringify(token), (err: Error) => {
          if (err) throw err;
        });
        return token;
      }
    
      private async send(mail: Mail.Options): Promise<void> {
        const mailComposer: MailComposer = new MailComposer(mail); // build mail with nodemailer
        mailComposer.compile().build((err: Error, msg: Buffer) => {
          if (err) throw err;
          this.gmailClient.users.messages.send(
            {
              userId: 'me',
              requestBody: {
                raw: GmailService.encodeMessage(msg),
              },
            },
            (err: Error, result: any) => {
              if (err) throw err;
              console.log('NODEMAILER reply from server', result.data);
            },
          );
        });
      }
    }
    

    【讨论】:

    • 这不是他们要的。他们希望在没有凭据的情况下运行应用程序,以便他们可以安全地共享代码。如果此代码在 GitHub 上发布,则将凭据存储在源代码中也会存在安全风险。
    • 我的建议是通过刷新令牌 api 使用凭证的属性并且不使用代码。而且我的代码不是将秘密存储为代码,而是从 github 秘密提供的。当然不包含在存储库源代码中
    【解决方案3】:

    你可以传递json对象而不是传递字符串

    {
       installed: "web",
       client_id: "<idhere>",
       client_secret: "<secrethere>",
       redirect_uris: ''
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-25
      • 1970-01-01
      • 2020-09-05
      • 2020-01-21
      • 2021-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多