如何在会话中访问令牌Shopify访问令牌

问题描述

我主要在前端工作,所以我对NodeJS不太熟悉。 我正在使用Shopify自定义应用程序,该应用程序的目的是在下订单时会收到webhook请求,并根据该请求将一些数据发送到其他API(计费应用程序)

我用shopify应用程序cli构建了shopify应用程序,而我的server.js文件是这样;

import "@babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth,{ verifyRequest } from "@shopify/koa-shopify-auth";
import graphQLProxy,{ ApiVersion } from "@shopify/koa-shopify-graphql-proxy";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
import session from "koa-session";
const { receiveWebhook } = require("@shopify/koa-shopify-webhooks");
import * as handlers from "./handlers/index";
dotenv.config();
const port = parseInt(process.env.PORT,10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
    dev,});
const handle = app.getRequestHandler();
const { SHOPIFY_API_SECRET,SHOPIFY_API_KEY,ScopES } = process.env;
app.prepare().then(() => {
    const server = new Koa();
    const router = new Router();

    server.use(
        session(
            {
                sameSite: "none",secure: true,},server
        )
    );
    server.keys = [SHOPIFY_API_SECRET];
    server.use(
        createShopifyAuth({
            apiKey: SHOPIFY_API_KEY,secret: SHOPIFY_API_SECRET,scopes: [ScopES],async afterauth(ctx) {
                //Auth token and shop available in session
                //Redirect to shop upon auth
                const { shop,accesstoken } = ctx.session;
                // This accesstoken is what I need on other scope

                ctx.cookies.set("shopOrigin",shop,{
                    httpOnly: false,sameSite: "none",});

                // Register Webhook
                handlers.registerWebhooks(
                    shop,accesstoken,"ORDERS_PAID","/webhooks/orders/paid",ApiVersion.October20
                );

                console.log(accesstoken);

                ctx.redirect("/");
            },})
    );

    const webhook = receiveWebhook({ secret: SHOPIFY_API_SECRET });
    router.post("/webhooks/orders/paid",webhook,(ctx) => {
        let user_id = ctx.state.webhook.payload.customer.id;

        console.log("received webhook,user_id: ",user_id);

        //console.log("ctx",ctx);

        // I need that accesstoken here to get some more info from Admin API with GraphQL
        let accesstoken = "???"
        
        handlers
            .graphqlRequest(
                accesstoken,"https://my-store.myshopify.com/admin/api/2020-10/graphql.json",`{
                    customer(id: "gid://shopify/Customer/${user_id}") {
                        email
                        Metafields(first: 5) {
                            edges {
                                node {
                                    key
                                    value
                                }
                            }
                        }
                    }
                }`
            )
            .then((res) => {
                console.log("res => ",res);
            })
            .catch((err) => {
                console.log("err => ",err);
            });
    });

    server.use(
        graphQLProxy({
            version: ApiVersion.October20,})
    );
    router.get("(.*)",verifyRequest(),async (ctx) => {
        await handle(ctx.req,ctx.res);
        ctx.respond = false;
        ctx.res.statusCode = 200;
    });
    server.use(router.allowedMethods());
    server.use(router.routes());
    server.listen(port,() => {
        console.log(`> Ready on http://localhost:${port}`);
    });
});

createShopifyAuth()方法使用我的应用程序密钥和应用程序api密钥获取一个accesstoken,我可以在afterauth()方法中使用它,但我也需要router.post()方法中的令牌来从中获取更多信息Shopify Admin API。

根据Shopify文档(或据我了解),该密钥在会话中可用,但如何访问该会话数据?或者我可以在router.push()中使用该令牌吗?

解决方法

仅为从管理面板登录应用程序的用户创建会话。在线访问令牌的创建方法就是这样。

如果您是从Webhook请求(又名不需要您重新登录应用程序的请求)中请求访问令牌的,则您将无法访问该会话,也将无法获取访问令牌。此外,会话在某些时候到期。

为了在Webhook请求中使用访问令牌,您需要创建一个无限期有效的offline访问令牌。 createShopifyAuth具有创建离线访问令牌的选项,您只需将accessMode: 'offline'添加到您的请求中(有关此here的更多信息)

示例:

createShopifyAuth({
      apiKey: SHOPIFY_API_KEY,secret: SHOPIFY_API_SECRET_KEY,accessMode: 'offline',scopes: ['read_products','read_orders'],

创建脱机访问令牌后,您需要将其保存在数据库中(或以其他方式),并从webhook路由中请求它,以便发出graphql请求。

差不多就是这样。