我一直在试图获得我的spotify访问令牌和刷新令牌为我的react-native 应用程序和它一直给我严重的问题. https://docs.expo.dev/guides/authentication/#spotify 我能够使用useAuthRequest获取我的代码和状态.现在,我已经try 使用代码来获取我的访问令牌和刷新客户端上的应用程序的令牌,但我一直遇到错误400.因此,判断其他堆栈溢出问题,我意识到在服务器上处理它会更好,所以我决定创建一个express服务器来try 并获得访问代码.

router.post('/get-spotify-access-code',(req: Request, res: Response)=>{
  console.log(req.body)
  const accessCode = req.body;
  var authOptions:AuthOptions = {
    url: 'https://accounts.spotify.com/api/token',
    form: {
      code: accessCode,
      redirect_uri: redirectUri,
      grant_type: 'authorization_code'
    },
    headers: {
      'content-type': 'application/x-www-form-urlencoded',
      'Authorization': 'Basic ' + Buffer.from(clientID + ':' + clientSecret).toString('base64')
    },
    json: true
  };
  request.post(authOptions, (error: any, response:any, body:any)=>{
    console.log(error);
    console.log(response)
    if(!error && response.statusCode === 200){
      const access_token = body.access_token;
      const refresh_token = body.refresh_token;
      const expires_in = body.expires_in;
      res.json({
          'access_token': access_token,
          'refresh_token': refresh_token,
          'expires_in': expires_in
      });
    }
  })      
})

但我仍然得到错误400,我似乎不能找出它.我真的很感激你的回应.下面是我如何处理react本地应用程序的代码,

const [request2, response2, promptAsync2] = useAuthRequest({
        clientId: clientID,
        clientSecret: clientSecret,
        scopes: [
            'user-read-playback-state',
            'user-modify-playback-state',
            'user-read-currently-playing',
            'streaming',
            'playlist-read-private',
            'playlist-read-collaborative',
            'playlist-modify-private',
            'playlist-modify-public',
            'user-follow-modify',
            'user-follow-read',
            'user-read-playback-position',
            'user-library-modify',
            'user-library-read',
            'user-read-email',
            'user-read-private'
        ],
        usePKCE: false,
        redirectUri: makeRedirectUri({
            scheme: undefined
        })
    },
        discovery
    )
    useEffect(() => {
        if (response2?.type === 'success') {
            // get spotify access code
             const { code } = response2.params;
            const getSpotifyCode = async() =>{    
                const code2 = {
                    code
                }
                await axios.post('http://localhost:8005/get-spotify-access-code', code2).then(
                response =>{
                    console.log(response);
                }
               ).catch(error =>{
                console.log(error)
               })
            }
           getSpotifyCode()
        }
    }, [response2])

推荐答案

你应该匹配同一端口

运行Expo端口和Spotify开发者仪表板中端口的重定向URI之间.

我的重定向URL端口是3000

https://developer.spotify.com/dashboard

enter image description here

expo 运行港口为3000

package.json中

  "scripts": {
    "start": "expo start --port 3000",
    "android": "expo start --android --port 3000",
    "ios": "expo start --ios --port 3000",
    "web": "expo start --web --port 3000"
  },

Demo code

App.js

import * as React from 'react';
import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
import { Button, View, Text, StyleSheet } from 'react-native';
import axios from 'axios';

WebBrowser.maybeCompleteAuthSession();

// Endpoint
const discovery = {
  authorizationEndpoint: 'https://accounts.spotify.com/authorize',
  tokenEndpoint: 'https://accounts.spotify.com/api/token'
};

const PORT = 3000; // Corrected: PORT should not be part of the config object
const CLIENT_ID = '<your client id>';
const CLIENT_SECRET = '<your client secret>';
const REDIRECT_URI = `http://localhost:${PORT}/callback`; // your redirect URI

export default function App() {
  const [request, response, promptAsync] = useAuthRequest(
    {
      clientId: CLIENT_ID,
      clientSecret: CLIENT_SECRET,
      scopes: ['user-read-email', 'playlist-modify-public'],
      usePKCE: false,
      redirectUri: REDIRECT_URI,
    },
    discovery
  );

  const [accessToken, setAccessToken] = React.useState("mockAccessToken");
  const [refreshToken, setRefreshToken] = React.useState("mockRefreshToken");

  React.useEffect(() => {
    if (response?.type === 'success') {
      const { code } = response.params;
      // Exchange code for access token and refresh token
      axios.post(
        'https://accounts.spotify.com/api/token',
        new URLSearchParams({
          'grant_type': 'authorization_code',
          'redirect_uri': REDIRECT_URI,
          'code': code
        }).toString(),
        {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
          },
          auth: {
            username: CLIENT_ID,
            password: CLIENT_SECRET
          }
        }
      )
        .then((response) => {
          setAccessToken(response.data.access_token);
          setRefreshToken(response.data.refresh_token);
        })
        .catch((error) => {
          console.error('Error exchanging code for token:', error);
        });
    }
  }, [response]);


  return (
    <View style={styles.container}>
      <Button
        disabled={!request}
        title="Login"
        onPress={() => {
          promptAsync();
        }}
      />
      {accessToken && (
        <Text style={styles.tokenText}>Access Token: {accessToken}</Text>
      )}
      {refreshToken && (
        <Text style={styles.tokenText}>Refresh Token: {refreshToken}</Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  tokenText: {
    marginBottom: 20,
    fontSize: 16,
  },
});

package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start --port 3000",
    "android": "expo start --android --port 3000",
    "ios": "expo start --ios --port 3000",
    "web": "expo start --web --port 3000"
  },
  "dependencies": {
    "@expo/metro-runtime": "~3.1.3",
    "@expo/vector-icons": "^14.0.0",
    "axios": "^1.6.8",
    "expo": "~50.0.14",
    "expo-auth-session": "~5.4.0",
    "expo-status-bar": "~1.11.1",
    "expo-web-browser": "~12.8.2",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.73.6",
    "react-native-paper": "4.9.2",
    "react-native-web": "~0.19.6"
  }
}

Install dependencies

npm install

Run it

npm run web

Result

enter image description here

Node.js相关问答推荐

在child_Process中持久运行SSH命令

如何使用jq将依赖项添加到package.json中

在Node.js下使用PostgreSQL客户端聚合PostgreSQL中的用户定义类型

如何防止Socket-io实例化React/Next.js中的两个套接字(当前在服务器*和*客户端实例化)

函数声明中的异步在没有等待的函数中做什么?

有没有办法判断 UUID 是否是使用 node.js 中的特定命名空间生成的?

未授权使用联合身份未授权用户角色从 Amplify graphQL 访问类型 Y 上的 X

为什么这个 module.export 函数如果我直接传递它就不起作用,但如果我将它包装在一个匿名函数中就可以工作

等待不在 Express.js 中处理 res.app.render

加速 sequelize ORM 中的查询

为什么我的 Cypress Post 请求的请求正文是空的?

使用 Forms API 进行批量更新时生成 itemId

用户与mongoose 的完美搭配

带权限的机密 Rest-Api - 总是 403 - 我做错了什么?

什么是nestjs错误处理方式(业务逻辑错误vs.http错误)?

如何使用 Puppeteer 从输入中删除现有文本?

错误:大多数中间件(如 bodyParser)不再与 Express Bundle

tsconfig.json 中模块类型的区别

PhoneGap/Cordova Android 开发

Npm postinstall 仅用于开发