为其市场构建 Stripe 应用程序时创建授权流程的目的是什么

问题描述 投票:0回答:1

我正在为其市场构建一个条带应用程序,它有两种不同的方式来执行我所说的服务器调用。

一个是此图中表示的服务器端逻辑

另一个是此图中表示的授权流程

现在谈谈我想要实现的目标。

我有一个从该平台入门套件分叉的 Next JS 应用程序 https://github.com/vercel/platforms

我最初根据此处的服务器端逻辑文档设置了一条路由来验证条带签名https://stripe.com/docs/stripe-apps/build-backend

单击 Stripe App 仪表板 UI 上的按钮后,我能够验证签名,我在 Next JS 应用程序上验证了签名

然后,我使用

isVerifiedToSignUp
true
创建一个 Stripe Secret,这样我就可以在查找秘密时在 Stripe UI 中显示一个按钮,该按钮显示我的应用程序的登录链接。

所以首先他们授权,然后他们会获得登录链接

const secret = await stripe.apps.secrets.create({
        scope: { type: 'user', user: body.user_id },
        name: "isAuthorizedToSignup",
        payload: true,
      });

      const createStripeVerify = async () => {
        try {
          const stripeVerifyCreation = await prisma.stripeVerify.create({
            data: {
              userId: body.user_id,
              accountId: body.account_id,
              verified: verify,
            },
          });
      
        } catch (error) {
          console.error("Error in creating stripe verify entry:", error);
        }
      }

然后我在数据库中创建 stripeVerify 模型下的一些记录

然后,一旦用户在条带仪表板中单击“登录”,就会定向到我的

http://app.localhost:3000/login?userId=123&accountId=123

此时他们可以登录,该页面有一个服务器端功能,可以在 stripeVerify 下的数据库中查找 userId 并确认它存在。如果不是,它会重定向到未经授权的。这样用户只能通过 Stripe 应用程序仪表板注册应用程序,而不能通过访问 /login 来注册。

现在,一旦他们登录(使用 github),他们就会返回登录,其中有一个中间件可以检查会话,重定向到

app.localhost:3000/?userId=123&accountId=123
并加载仪表板。

然后在该页面上运行更新函数,因为我还传递了 url 参数,以更新刚刚使用名为 stripeUserId:123 的字段创建的用户。

现在我有了一个功能正常的应用程序,其 Stripe 用户 ID 与我的用户表结合在一起。

这是我开始感到困惑的地方

这个功能让我接下来可以做什么。

我可以简单地从我的应用程序通过 UserID 调用 Users Stripe 仪表板吗,因为我只有用于 stripe 的 api 密钥。

如果我想做 Next JS App 向用户 stripe 帐户发送请求,我的设置可以吗?

我感觉不是。

这就是 Oauth Flow 的用武之地吗?

根据图表,Stripe 应用程序可以与我的应用程序共享相同的 Oauth(如果已设置)。它允许我做什么,从 Stripe 应用程序向我的 Next JS 应用程序发出请求。

在这种情况下,我是否只想对我的应用程序运行服务器端逻辑获取请求,检查签名,然后在我的 Next JS 应用程序中运行数据库调用或其他内容。

举例来说,我想要一个条带产品,当它创建时自动向我的 Next JS 应用程序发送请求,它在我的模型中创建一个帖子

model Post {
  id            String   @id @default(cuid())
  title         String?  @db.Text
  description   String?  @db.Text
  content       String?  @db.Text
  slug          String   @default(cuid())
  image         String?  @default("123.png") @db.Text
  imageBlurhash String?  @default("data:image/png;base64,123") @db.Text
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt
  published     Boolean  @default(false)
  site          Site?    @relation(fields: [siteId], references: [id], onDelete: Cascade, onUpdate: Cascade)
  siteId        String?
  user          User?    @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
  userId        String?

  @@unique([slug, siteId])
  @@index([siteId])
  @@index([userId])
}

我所做的就是监听用于创建条带产品的 Webhook。

如何将其构建到我的 Stripe 应用程序中?

这是我想创建的第一个功能。

最后,如果您查看上面的 oAuth 图,我还有一个关于 oauth 流程的最后一个问题

我在这里添加了注释

这是使用访问令牌对我的 Next JS 应用程序发出的请求吗?

我必须在 Next JS 应用程序中做什么才能实现此目的?

如果有人想进一步了解我的问题,我还在异想天开中创建了这个图表

https://whimsical.com/stripe-app-next-js-app-8DzXSq4LtKf32CcQQSaoLZ

next.js oauth multi-tenant next-auth stripe-apps
1个回答
0
投票

这解决了我的问题

按照此处的步骤 1、2、3 和 3 https://stripe.com/docs/stripe-apps/api-authentication/oauth

一旦获得应用程序的安装链接,就可以在 Next JS 中实现 oAuth 了


import { NextApiRequest, NextApiResponse } from "next";
import btoa from 'btoa'; // You might need to install the 'btoa' package
// Use environment variables for the API key
const STRIPE_API_KEY = process.env.NODE_ENV === 'production' ? process.env.STRIPE_PRODUCTION : process.env.STRIPE_TEST;
const encodedKey = btoa(STRIPE_API_KEY + ":");

// Utility function for setting CORS headers
const setCORSHeaders = () => ({
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
  "Access-Control-Allow-Headers":
    "Content-Type, stripe-signature, Authorization",
});

// Your API endpoint
export async function POST(req: NextApiRequest, res: NextApiResponse) {
  try {
    const body = await req.json();
    const stripeOAuth = await fetch("https://api.stripe.com/v1/oauth/token", {
      method: "POST",
      headers: {
        Authorization: `Basic ${encodedKey}`,
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body: new URLSearchParams({
        code: body.code.value,
        grant_type: "authorization_code",
      }),
    })
      .then((response) => response.json())
      .then((data) => {
        // console.log("stripe-oauth", data);
        return data;
      })
      .catch((error) => {
        console.error("Error:", error);
      });

    const stripeOAuthRefresh = await fetch(
      "https://api.stripe.com/v1/oauth/token",
      {
        method: "POST",
        headers: {
          Authorization: `Basic ${encodedKey}`,
          "Content-Type": "application/x-www-form-urlencoded",
        },
        body: new URLSearchParams({
          refresh_token: stripeOAuth.refresh_token,
          grant_type: "refresh_token",
        }),
      },
    )
      .then((response) => response.json())
      .then(async (data) => {
        return data;
      })
      .catch((error) => {
        console.error("Error:", error);
      });

    return new Response(
      JSON.stringify({
        stripeOAuth: stripeOAuth,
        stripeOAuthRefresh: stripeOAuthRefresh,
      }),
      {
        status: 200,
        headers: {
          ...setCORSHeaders(),
          "Content-Type": "application/json",
        },
      },
    );
  } catch (error) {
    // Check if error is an instance of Error
    if (error instanceof Error) {
      console.error("Error in POST request:", error.message);
      return new Response(error.message, {
        status: 500, // Internal Server Error
        headers: setCORSHeaders(),
      });
    } else {
      // Handle the case where the error is not an instance of Error
      console.error("An unknown error occurred:", error);
      return new Response("An unknown error occurred", {
        status: 500,
        headers: setCORSHeaders(),
      });
    }
  }
}

欲了解更多详情,您可以按照说明这里

© www.soinside.com 2019 - 2024. All rights reserved.