【问题标题】:How to save result of /api/page to state如何将 /api/page 的结果保存到状态
【发布时间】:2022-02-14 11:38:15
【问题描述】:

我正在尝试对 Xero 的 API 进行身份验证。我得到一个“代码”,然后将其交换为 access_token。我还是 NextJS 和 React 的新手,所以我可能没有正确考虑这个问题。

我的代码导致返回正确的数据,但是我不知道如何在应用程序的其余部分有效地使用它。我不知道如何在自定义提供程序中使用 NextAuth,因此尝试自己推出。

  • 用户单击“连接到 Xero”按钮 - 这是启动该过程并将用户带到 Xero 以在浏览器中登录的 href。用户进行身份验证。 Xero 调用回调
  • /api/callback 处的回调响应
  • 我提取“代码”,然后向 Xero 发出后续请求,将其交换为访问令牌。

这是我卡住的地方 - 因为初始操作是 href 重定向,我不确定如何将最终 API 结果作为状态/可用的东西返回到我的代码中。实际上,Xero 正在调用 api/callback 页面,这就是用户所在的位置。

我尝试将 useState 钩子放入 api/callback 中,但这违反了钩子规则。

非常感谢任何指针。

代码;

pages/index.js

import React from 'react'
import Layout from '../components/Layout'
import TopNav from '../components/TopNav'
import Link from 'next/link';   

export default function Main(props) { 
  
  const test = props.URL

  return (
    <>
      <Layout>
        <TopNav name="Main page"/>  
        <p>this is the main page</p>
        
        <Link href={test} passHref={true}>
          <button className=' w-40 border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium sm:flex-1'>
            Connect to Xero
          </button>
        </Link>
      </Layout>    
    </>
  )
}

export async function getStaticProps() {
  const XeroAuthURL = "https://login.xero.com/identity/connect/authorize?response_type=code&client_id="
  const client_ID = process.env.XERO_CLIENT_ID
  const redirect_uri = process.env.XERO_REDIRECT_URI
  const scope = "offline_access openid profile email accounting.settings"

  const URL = `${XeroAuthURL}${client_ID}&redirect_uri=${redirect_uri}&scope=${scope}` 
  
  return {
    props: {
      URL: URL
    },
  };
}

/api/callback.js

import axios from "axios"
const qs = require('qs');

export default async function callback(req, res) {
    
    try {
        //callback from Xero will deliver the code, scope + state (if given)
        //https://developer.xero.com/documentation/guides/oauth2/auth-flow/#2-users-are-redirected-back-to-you-with-a-code
        console.log(`REQ = ${JSON.stringify(req.query)}`)
            
        
       //exchange code for tokens - https://developer.xero.com/documentation/guides/oauth2/auth-flow/#3-exchange-the-code
        var data = qs.stringify({
            'code': req.query.code,
            'grant_type': 'authorization_code',
            'redirect_uri': 'http://localhost:3000/api/callback' 
          });
            
        var config = {
            method: 'post',
            url: 'https://identity.xero.com/connect/token',
            headers: { 
                'Content-Type': 'application/x-www-form-urlencoded', 
                'Authorization': 'Basic **put your authorisation result here**'
            },
            data : data
        };

        try {
            const response = await axios(config)
            //response has the data I want to put into State
            console.log(JSON.stringify(response.data));
              //save data off here somehow???
              //tried redirecting but unsure if can pass the result
              res.redirect(307, '/')

        } catch (error) {
            console.error(error)
            res.status(error.status || 500).end(error.message)
        }
            
        
    } catch (error) {
      console.error(error)
      res.status(error.status || 500).end(error.message)
    }
  }

【问题讨论】:

  • 您是否考虑过使用 cookie 将您需要的任何数据传递给您的应用程序?
  • 我实际上没有 - 这是个好主意,谢谢。鉴于这只是在我添加一些永久存储之前,cookie 暂时是完美的。

标签: react-hooks next.js xero-api


【解决方案1】:

添加了一个我可以在测试时使用的不安全 cookie。不要在生产中使用它,因为 cookie 不是 httpOnly 且不安全。

import axios from "axios"
import Cookies from 'cookies'
const qs = require('qs');

export default async function callback(req, res) {
    
    const cookies = new Cookies(req,res)
    try {
    
        var data = qs.stringify({
            'code': req.query.code,
            'grant_type': 'authorization_code',
            'redirect_uri': 'http://localhost:3000/api/callback' 
          });
            
        var config = {
            method: 'post',
            url: 'https://identity.xero.com/connect/token',
            headers: { 
                'Content-Type': 'application/x-www-form-urlencoded', 
                'Authorization': 'Basic **YOUR AUTH CODE HERE**'
            },
            data : data
        };

        try {
            var response = await axios(config)
            response.data.expires_at = Date.now() + response.data.expires_in*1000
              //save data off
              //TO DO - THIS IS REALLY BAD - ONLY USE THIS TEMPORARILY UNTIL HAVE GOT PERMSTORAGE SETUP
              cookies.set('myCookieName', JSON.stringify(response.data), {
                secure: false,
                httpOnly: false
              }
            )
              res.redirect(307, '/')
              //return ({ data: response.data })

        } catch (error) {
            console.error(error)
            res.status(error.status || 500).end(error.message)
        }
            
        
    } catch (error) {
      console.error(error)
      res.status(error.status || 500).end(error.message)
    }
  }

然后在索引中;

import React from 'react'
import Layout from '../components/Layout'
import TopNav from '../components/TopNav'
import Link from 'next/link';   
import { getCookie } from 'cookies-next';

export default function Main(props) { 
  
  //check for cookie
  //TO DO THIS IS REALLY BAD; CHANGE WHEN GET PERM STORAGE ORGANISED
  const cookie = getCookie('myCookieName');

  const URL = props.URL
  
  return (
    <>
      <Layout>
        <TopNav name="Main page"/>  
        <p>this is the main page</p>
        
        <Link href={URL} passHref={true}>
          <button className=' w-40 border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium sm:flex-1'>
            Connect to Xero
          </button>
        </Link>
        <p>{cookie ? cookie : 'waiting for cookie...'}</p>
      </Layout>    
    </>
  )
}



export async function getStaticProps() {
  const XeroAuthURL = "https://login.xero.com/identity/connect/authorize?response_type=code&client_id="
  const client_ID = process.env.XERO_CLIENT_ID
  const redirect_uri = process.env.XERO_REDIRECT_URI
  const scope = "offline_access openid profile email accounting.settings"

  //console.log(`URL - ${XeroAuthURL}${client_ID}&redirect_uri=${redirect_uri}&scope=${scope}`)
  const URL = `${XeroAuthURL}${client_ID}&redirect_uri=${redirect_uri}&scope=${scope}` 
  
  return {
    props: {
      URL: URL,
    },
  };
}

【讨论】:

    猜你喜欢
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-16
    • 2013-04-29
    • 1970-01-01
    • 2014-05-06
    相关资源
    最近更新 更多