使用 React 进行 Firebase Google 登录
介绍
Firebase 身份验证提供了一种使用用户现有社交帐户登录的简便方法。在本教程中,我们将研究如何使用用户的 Google 帐户登录。
我将向你展示
- 设置 Firebase 项目。
- 初始化 Firebase 应用。
- 在 Firebase 中启用用户身份验证。
- 使用社交服务提供商登录用户
- 使用 Context API 向子组件提供身份验证状态。
- 保护路线,即只允许经过身份验证的用户访问路线。
- 处理用户注销
要求
- 至少Node 8.10 和 npm >= 5.6
- 对 React Hooks 的基本理解
入门代码
克隆启动代码git clone -b starter https://github.com/gathoni-k/Firebase-Google-Signin.git
首先,前往此处创建项目
点击“开始”按钮, 您将进入项目页面。选择“添加项目”,并为您的项目指定任意名称。您可以选择是否使用 Google Analytics(谷歌分析),并选择 Firebase 帐户,您可以选择默认帐户。 稍后,您将进入项目概览页面。
要添加应用程序,请在“开始...”文本下方单击第三个图标,这将允许您创建一个 Web 应用程序并为您的 Web 应用程序指定一个昵称。
单击下一步并复制 firebaseConfig 对象,我们稍后将使用它来初始化我们的应用程序。
要启用身份验证,请返回项目概览页面并单击“身份验证”选项卡,然后设置登录方法并启用 Google
。
好吧,现在开始有趣的事情...... 💃🏾💃🏾
让我们首先抓取之前抓取的 Firebase 配置对象,因为这些是敏感信息,我们需要将其存储在 .env 文件中并将其添加到 .gitignore 文件中,这样我们就不会错误地将其推送到 GitHub 等版本源控制提供商。
话虽如此,在根文件夹中创建一个 .env 文件并添加以下内容
.env
REACT_APP_API_KEY=""
REACT_APP_AUTH_DOMAIN=""
REACT_APP_DATABASE_URL=""
REACT_APP_PROJECT_ID=""
REACT_APP_STORAGE_BUCKET=""
REACT_APP_MESSAGING_SENDER_ID=""
REACT_APP_APP_ID=""
REACT_APP_MEASUREMENT_ID=""
现在使用我们之前获取的 Firebase 配置对象中的相应值来填充它。
注意,REACT_APP_ 前缀是必需的。你可以在这里阅读更多关于在 React 中设置自定义环境变量的信息。
要访问 .env 变量,我们必须安装 dotenv。这是一个 npm 包,可以将 .env 文件中的环境变量加载到 process.env 中。
yarn add dotenv
安装 Firebase
yarn add firebase
现在让我们把所有这些都用起来
创建一个服务文件夹并在其中创建 firebase.js 文件并添加以下代码
src/services/firebase.js
import dotenv from 'dotenv'
dotenv.config()
import * as firebase from "firebase/app";
import "firebase/auth";
firebase.initializeApp({
apiKey: process.env.REACT_APP_API_KEY,
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_DATABASE_URL,
projectId: process.env.REACT_APP_PROJECT_ID,
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID
});
在上面的代码中:
- 我们已经导入了 dotenv 并对其进行了配置。
- 导入 Firebase
- 初始化 Firebase 应用 接下来创建一个登录函数,用于使用 Google 账号登录。我们将使用该
signInWithPopup()
方法。
src/services/firebase.js
export const auth = firebase.auth();
const googleProvider = new firebase.auth.GoogleAuthProvider()
export const signInWithGoogle = () => {
auth.signInWithPopup(googleProvider).then((res) => {
console.log(res.user)
}).catch((error) => {
console.log(error.message)
})
}
要使用此功能,我们必须将其导入 Login.js 文件并向登录按钮添加 onClick 处理程序。
src/Login.js
import React from "react";
import "./Login.css"
import { signInWithGoogle } from "./services/firebase";
export default function Login() {
return (
<div className="login-buttons">
<button className="login-provider-button" onClick={signInWithGoogle}>
<img src="https://img.icons8.com/ios-filled/50/000000/google-logo.png" alt="google icon"/>
<span> Continue with Google</span>
</button>
</div>
);
}
就这样,您现在可以通过用户的 Google 帐户登录了。
但是,如何防止未经授权的用户访问受保护的路由呢?方法有很多,但我将向您展示如何使用 context API。context API 是一种定义全局变量的方法,这些变量可以通过您的组件访问,而无需将 props 从一个组件传递到另一个组件(即 prop 钻取)。
创建一个 Providers 文件夹并在其中创建一个 UserProvider.js 文件
src/providers/UserProvider.js
import React, {useState, useEffect, createContext} from "react";
import { auth } from "../services/firebase"
export const UserContext = createContext({user: null})
export default () => {
const [user, setuser] = useState(null)
useEffect(() => {
auth.onAuthStateChanged(async (user) => {
const { displayName, email } = user;
setuser({
displayName,
email
})
})
},[])
return (
<UserContext.Provider value={user}>{props.children}</UserContext.Provider>
)
}
要理解上述代码,首先必须了解 context API。
我们将用户值存储为 context,因此我们使用 createContext() 创建它,并传入用户的初始值(在本例中为 null),然后赋值给变量 UserContext。UserContext
将返回提供值的 Provider 组件。在本例中,它将返回用户。
在默认函数中,我们必须跟踪用户的身份验证状态。这可以通过 onAuthStateChanged 函数完成,该函数由 firebase.auth() 提供,我们在 firebase.js 应用中将其导出为 auth。
用户登录后,状态将更新为其显示名称和电子邮件。
最后,该函数返回包含用户值的 UserContext Provider 组件。
要使用这些值,我们必须将我们想要使用用户值的组件与 UserProvider 组件包装在一起。
src/App.js
import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import "./App.css"
import Navbar from "./Navbar"
import Login from "./Login";
import Dashboard from "./Dashboard";
import UserProvider from "./providers/UserProvider";
function App() {
return (
<UserProvider>
<Router>
<Navbar/>
<div className="App">
<Switch>
<Route exact path="/">
<Login />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
</Router>
</UserProvider>
);
}
export default App;
用户值现在可以通过 useContext 钩子供我们的组件使用。
src/Login.js
import React, { useContext } from 'react';
import './Login.css'
import { signInWithGoogle } from './services/firebase';
import { UserContext } from './providers/UserProvider';
export default function Login() {
const user = useContext(UserContext)
return (
<div className="login-buttons">
<button className="login-provider-button" onClick={signInWithGoogle}>
<img src="https://img.icons8.com/ios-filled/50/000000/google-logo.png" alt="google icon"/>
<span> Continue with Google</span>
</button>
</div>
);
}
现在怎么办?
现在我们检查用户值,如果通过身份验证,则重定向到仪表板页面
src/Login.js
import React, { useEffect, useContext, useState } from 'react';
import './Login.css'
import { signInWithGoogle } from './services/firebase';
import { UserContext } from './providers/UserProvider';
import { Redirect } from 'react-router-dom';
export default function Login() {
const user = useContext(UserContext)
const [redirect, setredirect] = useState(null)
useEffect(() => {
if (user) {
setredirect('/dashboard')
}
}, [user])
if (redirect) {
<Redirect to={redirect}/>
}
return (
<div className="login-buttons">
<button className="login-provider-button" onClick={signInWithGoogle}>
<img src="https://img.icons8.com/ios-filled/50/000000/google-logo.png" alt="google icon"/>
<span> Continue with Google</span>
</button>
</div>
);
}
这里有一些新东西。首先是重定向状态和 useEffect 钩子。useEffect
钩子将在组件渲染后运行。它会检查用户值,如果存在,则表示用户已通过身份验证,可以重定向到仪表板。
通过将重定向设置为仪表板路径,我们可以正确地重定向用户。太棒了!
但有一个问题,如果用户访问 /dashboard,他们仍然可以访问。我们真的不希望出现这种情况。
为了保护 dashboard 路由,我们必须检查用户的身份验证状态。如果通过身份验证,他们就可以继续访问;如果未通过身份验证,我们会将他们重定向到登录页面,并将其踢出。
src/DashBoard.js
import React from "react";
import "./Dashboard.css";
import React, { useEffect, useContext, useState } from "react";
import { UserContext } from "./providers/UserProvider";
import { Redirect } from "react-router-dom";
export default function Dashboard() {
const user = useContext(UserContext);
const [redirect, setredirect] = useState(null);
useEffect(() => {
if (!user) {
setredirect("/");
}
}, [user]);
if (redirect) {
<Redirect to={redirect} />;
}
return (
<div className="dashboard">
<h1 className="dashboard-text">Welcome Home</h1>
<button className="logout-button">
<img
src="https://img.icons8.com/ios-filled/50/000000/google-logo.png"
alt="google icon"
/>
<span> logout</span>
</button>
</div>
);
}
现在要注销,这很简单。我们只需要调用auth.signOut()
我们的firebase.js文件,导入函数,并为注销按钮添加一个onClick处理程序。
src/services/firebase.js
...
export const logOut = () => {
auth.signOut().then(()=> {
console.log('logged out')
}).catch((error) => {
console.log(error.message)
})
}
src/Dashboard.js
import React from "react";
import "./Dashboard.css";
import React, { useEffect, useContext, useState } from "react";
import { UserContext } from "./providers/UserProvider";
import { Redirect } from "react-router-dom";
import { logOut } from "./services/firebase";
export default function Dashboard() {
const user = useContext(UserContext);
const [redirect, setredirect] = useState(null);
useEffect(() => {
if (!user) {
setredirect("/");
}
}, [user]);
if (redirect) {
<Redirect to={redirect} />;
}
return (
<div className="dashboard">
<h1 className="dashboard-text">Welcome Home</h1>
<button className="logout-button" onClick={logOut}>
<img
src="https://img.icons8.com/ios-filled/50/000000/google-logo.png"
alt="google icon"
/>
<span> logout</span>
</button>
</div>
);
}
本教程有点长,但就是这样。
感谢阅读🥰
鏂囩珷鏉ユ簮锛�https://dev.to/gathoni/firebase-google-sign-in-with-react-3741