如何使用 Auth0 和 Cloudinary 通过 React 构建音乐流媒体应用 music-app-with-auth0-and-cloudinary

2025-06-07

如何使用 Auth0 和 Cloudinary 构建基于 React 的音乐流媒体应用

带有 auth0 和 cloudinary 的音乐应用程序

自诞生以来,流媒体音乐发展迅猛,如今已成为最受大众接受的音乐聆听方式之一。许多流媒体网站提供免费音乐,这不仅减少了盗版需求,也确保了艺术家获得公平的报酬。流媒体音乐也非常便捷,拥有无限可能。

在本教程中,我们将学习如何使用 Auth0 和 Cloudinary 开发音乐流应用程序。

沙盒

该项目是在Codesandbox中完成的。如需快速入门,请 fork Codesandbox或运行该项目。

GitHub 存储库:

带有 auth0 和 cloudinary 的音乐应用程序

使用 CodeSandbox 创建




什么是 Auth0?

Auth0是一个可扩展的身份验证和授权系统,设置简单。它还提供了一个完整的身份和访问管理系统,开箱即用,并可根据需要定制、扩展和开发新功能。

什么是 Cloudinary?

Cloudinary提供安全全面的 API,可从服务器端、浏览器或移动应用快速高效地上传媒体文件。我们可以使用 Cloudinary 的 REST API 或客户端库 (SDK) 上传媒体资源。这些 SDK 封装了上传 API,使其更易于与网站和移动应用集成。

创建新的 React 项目并安装依赖项

为了创建新项目,我们使用npx create-react-app命令在我们选择的目录中搭建一个新项目。

要安装依赖项,我们将使用以下命令:

cd <project name> 

npm install @auth0/auth0-react @supabase/supabase-js bootstrap moment react-audio-player react-bootstrap react-helmet
Enter fullscreen mode Exit fullscreen mode

一旦创建了应用程序并安装了依赖项,我们将看到一条消息,其中包含导航到我们的网站并在本地运行它的说明。我们用命令来执行此操作。

    npm start
Enter fullscreen mode Exit fullscreen mode

React.js 将启动一个热重载开发环境,默认可从http://localhost:3000访问

设置 Auth0 帐户

如果您还没有注册,请访问Auth0进行注册,或者登录仪表板,单击Applications下拉菜单application,最后单击Create Application如下所示的按钮:

cloudinary 演示

我们现在可以创建我们的应用程序,如下所示:

cloudinary 演示

如下所示,我们已经成功创建了我们的应用程序,但我们需要设置 URL 来指回我们的应用程序。

cloudinary 演示

向下滚动到应用程序 URI 部分并设置以下内容

Allowed Callback URLs= https://de7pd.csb.app
Allowed Logout URLs = https://de7pd.csb.app
Allowed Web Origins = https://de7pd.csb.app

将https://de7pd.csb.app替换为我们之前设置的应用程序 URL 或http://localhost:3000。在本教程的后面部分,我们将在应用程序中使用域和客户端 ID。

设置我们的应用程序 UI 和 Auth0 集成。

让我们导入并设置我们的应用程序,以使用我们安装的 bootstrap 依赖项。public/index.html通过使用以下代码片段链接 bootstrap 的 CSS 和 js 来更新文件:

  • 添加 CSS 引用
<!DOCTYPE html>
    <html lang="en">
      <head>
        //...

        <link
          rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css"
          integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU"
          crossorigin="anonymous"
        />
        <title>Music Streaming App</title>
      </head>
      <body>
        //...
      </body>
    </html>
Enter fullscreen mode Exit fullscreen mode
  • 添加 JS 引用
    <!DOCTYPE html>
    <html lang="en">
      <head>
      //...
      </head>
      <body>
        <noscript>
          You need to enable JavaScript to run this app.
        </noscript>
        <div id="root"></div>
        <script
          src="https://unpkg.com/react/umd/react.production.min.js"
          crossorigin
        ></script>
        <script
          src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"
          crossorigin
        ></script>
        <script
          src="https://unpkg.com/react-bootstrap@next/dist/react-bootstrap.min.js"
          crossorigin
        ></script>
      </body>
    </html>
Enter fullscreen mode Exit fullscreen mode

我们需要在主页上创建一个播放音乐的用户界面。我们将通过将app.js文件更新为组件来实现这一点。由于 React 的传统是使用组件结构,因此我们将在文件夹components中创建一个名为 的文件夹src,并创建header.jsmusic.jsmusicList.js组件。

components/music.js文件中,让我们用下面的代码片段来更新它:

    import ReactAudioPlayer from "react-audio-player";
    import moment from "moment";

    export default function Music({ musicList, index }) {
      return (
        <div className="col-md-4">
          <div className="card p-3 mb-2" key={index}>
            <div className="d-flex justify-content-between">
              <div className="d-flex flex-row align-items-center">
                <div className="icon">
                  {" "}
                  <i className="bx bxl-mailchimp"></i>{" "}
                </div>
                <div className="ms-2 c-details">
                  <h6 className="mb-0">{musicList.name}</h6>{" "}
                  <span>{moment(musicList.created_at).format("MMMM Do YYYY")}</span>
                </div>
              </div>
              <div className="badge">
                {" "}
                <span role="img" aria-label="">
                  Hot 🔥
                </span>{" "}
              </div>
            </div>
            <div className="mt-2">
              <h4 className="heading">{musicList.title}</h4>
              <div className="mt-2">
                <ReactAudioPlayer src={`${musicList.url}`} controls />
              </div>
            </div>
          </div>
        </div>
      );
    }
Enter fullscreen mode Exit fullscreen mode

musicList在上面的代码片段中,我们创建了一个包含和属性的单张音乐卡片组件index。我们还分别导入了 ReactAudioPlayer 和 moment 来设置音频播放器和上传日期的格式。

在组件内部musicList.js,我们将通过导入音乐组件并遍历示例 musicList 数组,使用下面的代码片段对其进行更新。

    import Music from "./music";

    export default function App() {
      const musicList = [
        {
          name: "olanetsoft",
          title: "Bang Bang",
          url: "https://res.cloudinary.com/demo/video/upload/dog.mp3",
          created_at:"2021-10-04T23:30:01.000Z",
        }
      ]
      return (
        <div className="row">
          {musicList.map((m, key) => (
            <Music musicList={m} index={key} />
          ))}
        </div>
      );
    }
Enter fullscreen mode Exit fullscreen mode

header.js让我们用下面的代码片段更新我们之前创建的组件:

    import { Button } from "react-bootstrap";

    export default function Header() {

      return (
        <div className="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
          <h5 className="my-0 mr-md-auto font-weight-normal">
            Music Streaming App with Auth0 and Cloudinary
          </h5>
          <nav className="my-2 my-md-0 mr-md-3">
            <a className="p-2 text-success" href="/">
              Home
            </a>
            <a className="p-2 text-danger" href="/">
              Trending
            </a>
            <a className="p-2 text-info" href="/">
              Top Songs
            </a>
          </nav>
            <Button
              id="btnUpload"
              className="btn margin"
              variant="primary"
            >
              Upload Song
            </Button>
        </div>
      );
    } 
Enter fullscreen mode Exit fullscreen mode

我们现在可以更新我们的src/app.js文件,如下所示:


    import MusicList from "../components/musicList";
    import "./styles.css";

    export default function App() {
      return (
        <div className="container mt-5 mb-3">
          <Header />
          <MusicList />
        </div>
      );
    }
Enter fullscreen mode Exit fullscreen mode

当前的用户界面看起来不太美观,我们将使用 CSS 添加一些样式。我们将src/styles.css在此 GitHub Gist 中使用以下内容更新文件。

.App {
font-family: sans-serif;
text-align: center;
}
body {
background-color: #00284e;
}
.card {
border: none;
border-radius: 25px;
}
.c-details span {
font-weight: 200;
font-size: 13px;
}
.badge span {
background-color: #fffbec;
width: 80px;
height: 30px;
padding-bottom: 5px;
border-radius: 5px;
display: flex;
color: #ff3c00;
justify-content: center;
align-items: center;
}
.spinner {
border: 1px solid;
position: fixed;
z-index: 1;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 50 50'%3E%3Cpath d='M28.43 6.378C18.27 4.586 8.58 11.37 6.788 21.533c-1.791 10.161 4.994 19.851 15.155 21.643l.707-4.006C14.7 37.768 9.392 30.189 10.794 22.24c1.401-7.95 8.981-13.258 16.93-11.856l.707-4.006z'%3E%3CanimateTransform attributeType='xml' attributeName='transform' type='rotate' from='0 25 25' to='360 25 25' dur='0.6s' repeatCount='indefinite'/%3E%3C/path%3E%3C/svg%3E")
center / 50px no-repeat;
}
.heading {
margin: 10px 0 5px;
text-transform: capitalize;
font-weight: 300;
font-size: 20px;
}
view raw styles.css hosted with ❤ by GitHub

我们的应用程序现在在http://localhost:3000/ 上看起来应该是这样的:

cloudinary 演示

我们目前正在处理样本数据,效果并不理想。我们应该能够上传和播放其他人上传的歌曲。

我们将使用 Auth0 来跟踪谁上传了新歌曲,然后我们将使用 Cloudinary 进行实际上传,再将其保存到数据库。

在我们的应用程序中设置 Auth0

让我们.env在项目的根目录中创建文件,并使用以下代码片段从我们的 Auth0 仪表板填充域和客户端 ID:

    AUTH0_DOMAIN=dev-9hbpo12k.us.auth0.com
    AUTH0_CLIENT_ID=tdYpNQ8Qqjymi0dOC7wZdGGWlYCN6FR3
Enter fullscreen mode Exit fullscreen mode

src/index.js让我们使用下面的代码片段导入Auth0Provider设置我们的应用程序:

    import { StrictMode } from "react";
    import ReactDOM from "react-dom";
    import App from "./App";
    import { Auth0Provider } from "@auth0/auth0-react";

    const domain = process.env.AUTH0_DOMAIN;
    const clientId = process.env.AUTH0_CLIENT_ID;

    const rootElement = document.getElementById("root");

    ReactDOM.render(
      <StrictMode>
        <Auth0Provider
          domain={domain}
          clientId={clientId}
          redirectUri={window.location.origin}
        >
          <App />
        </Auth0Provider>
        ,
      </StrictMode>,
      rootElement
    );
Enter fullscreen mode Exit fullscreen mode

我们现在可以使用下面的代码片段分别在文件夹中login-button.js创建logout-button.jsloading.js组件:components

里面components/login-button.js

    import { useAuth0 } from "@auth0/auth0-react";
    import { Button } from "react-bootstrap";

    export default function Login() {
      const { loginWithRedirect } = useAuth0();
      return (
        <Button
          id="btnLogin"
          className="btn margin"
          onClick={() => loginWithRedirect()}
          variant="primary"
        >
          Upload Music
        </Button>
      );
    }
Enter fullscreen mode Exit fullscreen mode

components/logout-button.js

    import { useAuth0 } from "@auth0/auth0-react";
    import { Button } from "react-bootstrap";

    export default function Logout() {
      const { logout } = useAuth0();
      return (
        <Button
          id="btnLogin"
          className="btn margin"
          onClick={() => logout()}
          variant="danger"
        >
          Logout
        </Button>
      );
    }
Enter fullscreen mode Exit fullscreen mode

然后里面components/loading.js

    import "../src/styles.css";
    export default function Loading() {
      return <div className="spinner"></div>;
    }
Enter fullscreen mode Exit fullscreen mode

我们可以继续导入之前创建的文件中的组件login如下所示:logoutheader.js

    import { useState, useEffect } from "react";
    import { Button } from "react-bootstrap";

    import { useAuth0 } from "@auth0/auth0-react";
    import Login from "../components/login-button";
    import Logout from "../components/logout-button";

    export default function Header() {
      const { isAuthenticated } = useAuth0();

      return (
        <div className="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
             {/*  */}
          {isAuthenticated ? (
            <>
              <div>
                <Button
                  id="btnUpload"
                  className="btn margin"
                  variant="primary"
                >
                  Upload Song
                </Button>
                &nbsp;&nbsp;
                <Logout />
              </div>
            </>
          ) : (
            <Login />
          )}
        </div>
      );
    }
Enter fullscreen mode Exit fullscreen mode

更新src/app.js

    //...
    import Loading from "../components/loading";

    export default function App() {
      const { isLoading } = useAuth0();
      if (isLoading) {
        return <Loading />;
      }
      return (
        //....
      );
    }
Enter fullscreen mode Exit fullscreen mode

让我们测试我们的应用程序,单击按钮后我们应该得到类似于下面的内容Upload Song

cloudinary 演示

cloudinary 演示

在上面的屏幕截图中,我们已成功登录,您会注意到标题中的 UI 已更改为包含注销按钮。

配置 Cloudinary 和 DB 以上传歌曲

我们将使用 Cloudinary 的上传小部件,因为它可以让我们从多个来源(包括 Dropbox、Facebook、Instagram)上传媒体资产。

创建一个免费的 cloudinary 帐户来获取您的云名称和 upload_preset。

上传预设使我们能够集中定义一组资产上传选项,而无需在每次上传调用时都提供它们。Cloudinary 云名称是与我们的 Cloudinary 帐户关联的唯一标识符。

首先,我们将通过内容分发网络 (CDN) 将 Cloudinary 小部件的 JavaScript 文件添加到位于 的 index.js 中。我们使用react-helmet的组件src/app.js来包含此文件,该组件允许我们在 React 中将数据添加到 HTML 文档的 Head 部分。<Helmet>

    //..

    import "./styles.css";

    import { Helmet } from "react-helmet";

    export default function App() {
      //...
      return (
        <div className="container mt-5 mb-3">
          <Helmet>
            <meta charSet="utf-8" />
            <script
              src="https://widget.Cloudinary.com/v2.0/global/all.js"
              type="text/javascript"
            ></script>
        //...
        </div>
      );
    }
Enter fullscreen mode Exit fullscreen mode

该小部件需要我们的 Cloudinarycloud_nameuploadPreset。该createWidget()函数创建一个新的上传小部件,并在成功上传视频或音频后,将资产的 public_id 分配给相关的状态变量。

为了获得我们的cloudnameuploadPreset我们按照以下步骤操作:

云名称是从我们的 Cloudinary 仪表板获得的,如下所示。

cloudinary 演示

我们可以在我们的 Cloudinary 设置页面的“上传”选项卡中找到上传预设,我们可以通过单击仪表板页面右上角的齿轮图标来访问它。

cloudinary 演示

然后我们点击Upload设置页面上的标签:

cloudinary 演示

我们向下滚动到页面底部的上传预设部分,在那里我们可以看到我们的上传预设,或者如果我们没有的话,可以看到创建预设的选项。

让我们components/header.js用下面的代码片段来更新我们的:

让我们在浏览器中打开我们的应用程序并单击Upload Song按钮;我们应该看到如下内容:

cloudinary 演示

我们可以使用本文档中的更多信息进一步定制小部件

我们已经在应用程序中成功配置和设置了 cloudinary,但我们还将集成一个supabase数据库来保存用户上传的所有歌曲。

让我们创建client.js将 supabase 与下面的 sippet 集成在一起的:

    import { createClient } from "@supabase/supabase-js";

    const URL = "https://kpriwlucrliyacagwjvk.supabase.co";
    const ANNON_PUBLIC_SECRET = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzMzM2NzU2OSwiZXhwIjoxOTQ4OTQzNgY5fQ.uBBXtyxbwKixUgql4tiYUsqOgSPyB4mLSc2kybqPCPI";

    export const supabase = createClient(
      URL,
      ANNON_PUBLIC_SECRET
    );
Enter fullscreen mode Exit fullscreen mode

要获取url密钥annon public,请创建一个supabasesettings帐户,启动一个新项目,然后转到Api选项卡。

我们将在侧边栏的表格编辑器选项卡中创建一个名为 的新表,其中songs包含 、 和 的列urlname确保title所有创建的列的列类型均为文本。

成功创建表后,让我们components/header.js使用下面的代码片段更新文件:

在上面的代码行中,

  • 我们创建了上传完成时更新的状态变量。
  • 我们创建了一个名为的函数createSong,它连接到中的歌曲表Supabase,然后我们输入数据。
  • createPost然后,我们在使用该方法将变量保存到数据库之前验证变量以确保它们不是未定义的。

让我们更新 musicList 组件以使用下面显示的代码片段检索所有上传的歌曲:

    import { useState, useEffect } from "react";
    import { supabase } from "../client";
    import Music from "./music";

    export default function App() {
      const [musicList, setMusicList] = useState([]);

      useEffect(() => {
        fetchSongs();
      }, []);

      async function fetchSongs() {
        const { data } = await supabase.from("songs").select();

        setMusicList(data);
      }

      return (
        <div className="row">
          {musicList.map((m, key) => (
            <Music musicList={m} index={key} />
          ))}
        </div>
      );
    }
Enter fullscreen mode Exit fullscreen mode

瞧🥳 一切就绪;我们现在可以成功上传歌曲、播放歌曲等。

cloudinary 演示

结论

本文介绍如何使用 Auth0 和 Cloudinary 构建利用 Cloudinary 小部件功能的音乐流应用程序。

资源

使用Auth0Cloudinary为Hackmamba Jamstack Content Hackathon创建的内容

文章来源:https://dev.to/hackmamba/how-to-build-a-music-streaming-app-with-react-using-auth0-and-cloudinary-6k9
PREV
这些是用于编码的最佳大型语言模型
NEXT
如何使用 Go、Templ 和 HTMX 技术概述构建全栈应用程序 先决条件 入门 在 Xata 上设置数据库 构建应用程序前端 将其组合并构建后端 结论