创建用于 Spotify 身份验证的 React 应用程序:如何使用 Flask 后端实现登录流程?

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

我正在尝试通过我的烧瓶后端中的spotipy 来验证用户身份验证,该后端是独立工作的。但是,当我尝试引入前端组件时,后端似乎没有发送正确的信息,或者前端获取了错误的信息。我尝试确保我从后端正确发送 cookie,并且我的缓存没有被用来记住用户是否登录。我对 Web 开发非常陌生,尤其是前端,所以任何帮助将不胜感激。

这是我期望我的代码发生的事情

  1. 在加载时检查缓存的令牌或用户身份验证状态。
  2. 如果未通过身份验证,则将用户重定向到 Spotify 登录。
  3. 处理来自 Spotify 的回调并检查身份验证状态。
  4. 重定向回 localhost:3000/ 我的前端所在的位置,以便它可以再次检查,这次应该显示用户已登录。

这是我后端的相关代码:

@app.route('/')
def index():
    cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
    auth_manager = spotipy.oauth2.SpotifyOAuth(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, redirect_uri=REDIRECT_URI, scope='user-read-currently-playing',
                                               cache_handler=cache_handler)
    

    if not auth_manager.validate_token(cache_handler.get_cached_token()):
        auth_url = auth_manager.get_authorize_url()
        #print(auth_url)
        return jsonify({"logged_in": False, "auth_url": auth_url})

    spotify = spotipy.Spotify(auth_manager=auth_manager)
    user_info = spotify.me()
    return jsonify({
        "logged_in": True,
        "user_info": {
            "display_name": user_info["display_name"],
            "id": user_info["id"],
            "uri": user_info["uri"],
            "profile_url": user_info["external_urls"]["spotify"]
        }
    })

@app.route('/callback')
def callback():
    code = request.args.get('code')
    print(code)
    if code:
        cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
        auth_manager = spotipy.oauth2.SpotifyOAuth(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, redirect_uri=REDIRECT_URI, scope='user-read-currently-playing',
                                                   cache_handler=cache_handler)
        auth_manager.get_access_token(code)
        session.modified = True
        response = make_response(redirect('http://localhost:3000/'))
        return response
    return 'Missing code parameter. Please try again.', 400

这是我的前端 App.js:

function App() {
  const [message, setMessage] = useState('');
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [authUrl, setAuthUrl] = useState('');
  
  useEffect(() => {
    const url = `http://127.0.0.1:5000/?t=${Date.now()}`;
    axios.get(url, { withCredentials: true })
      .then(response => { 
        const { logged_in, auth_url } = response.data;
        console.log(response.data);
        setIsLoggedIn(logged_in);
        if (!logged_in) {
          setAuthUrl(auth_url);
          console.log('Redirecting to:', auth_url);
        }
      })  
      .catch(error => console.error('Error:', error));
  }, []);

  return (
    <Router>
      <div className="App">
        <div className="App-header">
          <Routes>
            <Route path="/login" element={!isLoggedIn ? <Login authUrl={authUrl} /> : <Navigate to="/" />} />  // Use the Login component here
            <Route path="/" element={isLoggedIn ? <SearchBar onSearch={setMessage} /> : <Navigate to="/login" />} />    
          </Routes>
        </div>
      </div>
    </Router>
  );
}
export default App;

我做了一些测试,在回调函数中,如果我重定向回 localhost:5000,它会向我显示以下数据:

    "logged_in": True,
    "user_info": { etc etc...
        

这就是我希望前端检测到的内容。但由于某种原因,它仍然将 Logged_in 视为 false。

javascript python reactjs flask spotipy
1个回答
0
投票

当使用

spotipy
进行授权代码流程时,您不一定需要自己通过重定向来处理回调端点。

Spotipy
支持Spotify提供的多种身份验证流程,包括授权代码流程。

Spotipy
被描述为授权代码流的中间件时,这意味着
Spotipy
可以在 Python 应用程序中无缝处理大部分身份验证过程。

Spotipy 是中间件。 所以你不需要处理

./callback
端点。

演示

后端服务器由

Flask

import spotipy

from flask import Flask, session, jsonify
from flask_cookie_decode import CookieDecode
from spotipy.oauth2 import SpotifyOAuth
from flask_cors import CORS, cross_origin

CLIENT_ID = '<your client id>'
CLIENT_SECRET = '<your client secret>'
REDIRECT_URI = '<your redirect uri>' # get from developer dash board
username = '<your Spotify User id>'  # get from user profile
SCOPEs = ['user-read-currently-playing', 'user-read-recently-played']

# Create the Flask application
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'

app.config.update({'SECRET_KEY': 'MY_SECRET_KEY'})
cookie = CookieDecode()
cookie.init_app(app)

cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = SpotifyOAuth(client_id=CLIENT_ID,
                            client_secret=CLIENT_SECRET,
                            redirect_uri=REDIRECT_URI,
                            scope=SCOPEs,
                            username=username,
                            cache_handler=cache_handler)
auth_url = auth_manager.get_authorize_url()

@app.route('/get_logged')
@cross_origin()
def get_session():
    if (session and session['user']):
        return jsonify(dict(session))
    else:
        return jsonify({'logged_in': False, 'auth_url': auth_url})

@app.route('/clear_session')
@cross_origin()
def clear_session():
    session.clear()
    return jsonify({'session': 'cleared'})

@app.route('/login')
@cross_origin()
def login():
    auth_manager = SpotifyOAuth(client_id=CLIENT_ID,
                                client_secret=CLIENT_SECRET,
                                redirect_uri=REDIRECT_URI,
                                scope=SCOPEs,
                                username=username)
    if (session and session['user']):
        data = jsonify(dict(session).get('user')['user_info'])
        return data

    sp = spotipy.Spotify(auth_manager=auth_manager)
    user_info = sp.me()
    simple_user_info = {
        "logged_in": True,
        "user_info": {
            "display_name": user_info["display_name"],
            "id": user_info["id"],
            "uri": user_info["uri"],
            "profile_url": user_info["external_urls"]["spotify"]
        }
    }
    session['user'] = simple_user_info
    return jsonify(dict(session).get('user'))

if __name__ == '__main__':
    app.run()

Postman 的 API 测试

清除会话

GET http://localhost:5000/clear_session

登录

GET http://localhost:5000/get_logged

登录

GET http://localhost:5000/login

注意- 此 API 只能由 React 调用

前端代码

应用程序.js

import React, { useState } from 'react';
import axios from 'axios';

function App() {
  const [loggedIn, setLoggedIn] = useState(false);
  const [userData, setUserData] = useState(null);

  const handleLogin = async () => {
    try {
      const response = await axios.get('http://localhost:5000/login'); // Update URL if needed
      setUserData(response.data);
      setLoggedIn(true);
    } catch (error) {
      console.error('Error logging in:', error);
    }
  };

  return (
    <div>
      {loggedIn ? (
        <div>
          <h1>Welcome, {userData?.user_info?.display_name}</h1>
          <p>ID: {userData?.user_info?.id}</p>
          <p>URI: {userData?.user_info?.uri}</p>
          <a href={userData?.user_info?.profile_url}>Profile Link</a>
        </div>
      ) : (
        <div>
          <h1>Not logged in</h1>
          <button onClick={handleLogin}>Login with Spotify</button>
        </div>
      )}
    </div>
  );
}

export default App;

前端结果

http://localhost:3000/

参考文献

如何在flask中启用CORS

Flask 中的会话示例

flask-cookie 解码

如何获取client_id、client_secret和redirect_uri以及用户id

Spotipy 的当前播放列表

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