使用Firebase及其服务中的React应用中的身份验证。第3部分
#javascript #网络开发人员 #react #firebase

记录用户

现在,我们已经完成签名,并已将用户签名,接下来是将用户登录。返回我们的登录组件,让我们看看我们如何使用Firebase实现此目标。

但是首先,我们必须在输入中添加状态,然后开始实施该功能。

    import React, {useState} from 'react'
    import { Box, FormControl, FormLabel, Button, Heading, Text, VStack, Input, useToast } from '@chakra-ui/react'
    import { LoginCurve } from 'iconsax-react'
    import { app } from '../../firebaseConfig'
    import {getAuth, signInWithEmailAndPassword} from 'firebase/auth'
    import { useNavigate } from 'react-router-dom'

    const Login = () => {

      //initialise firebase auth
      const auth = getAuth();

      //initialise toast component from chakra Ui
      const toast = useToast();

      //initialise navigate from react-router-dom
      const navigate = useNavigate();

      //states for each of the imputs
      const [email, setEmail] = useState('')
      const [password, setPassword] = useState('');

      const handleClick = async  () => {
        if(email && password){
          try {
            await signInWithEmailAndPassword(auth, email, password).then((cred) => {
              console.log(cred.user);
              toast({
                title: "Login Successful.",
                description: "You have been logged in successfully!.",
                status: "success",
                duration: 3000,
                isClosable: true,
                variant: 'left-accent',
                position: 'top-right',

              });
              setEmail('');
              setPassword('');
              navigate('/profile')
            })
          } catch (error) {
            toast({
              title: "Error!",
              description: error.message,
              status: "error",
              duration: 3000,
              isClosable: true,
              variant: 'left-accent',
              position: 'top',
            });
          }
        }else{
          toast({
            title: "Error!",
            description: "Please fill in your details.",
            status: "error",
            duration: 3000,
            isClosable: true,
            variant: 'left-accent',
            position: 'top',
          });
        }
      }

      return (
        <Box mt='10'>
          <VStack spacing={6}>

            <Heading>Login</Heading>

            <Box maxW='400px'>
              <FormControl>
                <VStack spacing={4}>
                  <Box>
                    <FormLabel>Email</FormLabel>
                    <Input type='email' placeholder='Input your email' fontSize='14px' w='400px' value={email} onChange={(e) => setEmail(e.target.value)} />
                  </Box>

                  <Box>
                    <FormLabel>Password</FormLabel>
                    <Input type='password' placeholder='Input your password' fontSize='14px' w='400px' value={password} onChange={(e) => setPassword(e.target.value)} />
                  </Box>

                  <Box>
                    <Button type='submit' w='400px' colorScheme='teal' onClick={handleClick}>Login <LoginCurve style={{ marginLeft: '5px' }} /></Button>
                  </Box>
                </VStack>
              </FormControl>
            </Box>
          </VStack>
        </Box>
      )
    }

    export default Login

上面的代码是将状态添加到我们的输入并编写功能之后的登录组件的最终代码。当我们逐步通过代码库时,将代码复制并粘贴到代码编辑器中。

让我们从导入开始,我相信我们现在几乎熟悉signInWithEmailAndPassword()函数以外的几乎所有导入。此功能的作用是,它允许我们在注册期间用户早些时候提供的电子邮件和密码签署用户。然后,我们在handleSubmit()函数中调用该函数。如果一切顺利,则用户将登录,然后重定向到配置文件页面。如果出现任何问题,将显示出错误消息的错误吐司。

从Firebase Auth,Firestore数据库和Firebase存储中检索用户的数据

现在,我们已经能够使用他们的电子邮件和密码签署用户,并且我们能够将它们重定向到个人资料页面,以便每个用户可以查看他/她的个人资料,但是在个人资料页面上实际上没有任何内容,我们如何解决此问题?

我们可以以3个步骤进行操作。

  1. 第一件事是获取当前登录的用户,从那里我们可以获取用户的电子邮件和创建帐户的日期。
  2. 第二步是从firebase存储中获取用户的化身。
  3. 第三步是从Firestore数据库中获取用户的用户名和生物。
    import React, {useState, useEffect} from 'react'
    import {Box, Avatar, AvatarBadge, Text, Heading, Stack, Button, useToast} from '@chakra-ui/react'
    import {getAuth, signOut } from 'firebase/auth'
    import { getFirestore, query, where, getDocs, collection } from 'firebase/firestore'
    import { getStorage, ref, getDownloadURL } from 'firebase/storage'
    import { Link, useNavigate } from 'react-router-dom'
    import { app } from '../../firebaseConfig'


    const Profile = () => {
      const [currentUser, setCurrentUser] = useState(null);
      const [userDetails, setUserDetails] = useState('')
      const [avatar, setAvatar] = useState('');
      const auth = getAuth();
      const db = getFirestore();
      const storage = getStorage();
      const userRef = collection(db, 'user_data');
      const navigate = useNavigate();
      const toast = useToast();

      const signout = () => {
        signOut(auth).then(() => {
          navigate('/login');

          toast({
            title: "Logout Successful.",
            description: "You have been logged out successfully!.",
            status: "success",
            duration: 3000,
            isClosable: true,
            variant: 'left-accent',
            position: 'top-right',
          });

        })
      }

      const getCurrentUser = async () => {
        try {
          auth.onAuthStateChanged((user) => {
            console.log(user);
            setCurrentUser(user);
            const q = query(userRef, where('user_id', '==', user.uid));
            const avatarRef = ref(storage, user.uid);

            if(user){
              getDownloadURL(avatarRef).then((url) => {
                setAvatar(url);
                console.log(avatar);
              });

              getDocs(q).then(async (snapshot) => {
                let user_data = [];
                snapshot.docs.map((item) => {
                  user_data.push({ ...item.data(), id: item.id });
                  console.log(user_data);
                  return setUserDetails(user_data);
                })
                console.log(userDetails);
              });
            }
          })
        } catch (error) {
          console.log(error.message);
        }
      };

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

      const newDate = currentUser?.metadata.creationTime
      const date = new Date(newDate).toDateString();

      return (
        <>
        {currentUser ? 
        <Box maxW='400px' mt='16' bg='gray.100' p='5' borderRadius={5} boxShadow='md' display='flex' alignItems='center' justifyContent='center' mx='auto'>
          <Box>
            <Heading mb='5'>My Profile</Heading>
            <Avatar bg='teal' size='xl' mb='5' display='block' mx='auto' src={avatar}>
              <AvatarBadge boxSize='0.7em' bg='green.500' />
            </Avatar>
            <Stack spacing={4} fontWeight='semibold'>
              <Text>Username: {userDetails[0]?.user_name}</Text>
              <Text>Bio: {userDetails[0]?.user_bio}</Text>
              <Text>Email: {currentUser?.email}</Text>
              <Text>Date Joined: {date}</Text>
            </Stack>
            <Box textAlign='center' mt='7'>
              <Button colorScheme='teal' onClick={signout}>Logout</Button>
            </Box>
          </Box>
        </Box> 
        : 
        <Box mx='auto' mt='16'>
          <Heading fontWeight='semibold' fontSize={25} mb='3'>OOPS!</Heading>
          <Text mb='3'>You are not authorised to view this page, please login to get acces</Text>
          <Link to='/login'>
                <Button>Login</Button>
          </Link>
        </Box>}
        </>
      )
    }

    export default Profile

粘贴代码后,我们应该有一个UI,看起来像下面的图片。

profile page

就是这样,上面的代码适用于个人资料页面,它再次看起来很奇怪,但让我们一起通过。

就像我往常一样,我将从顶部的进口开始,我知道我们熟悉了我导入的大多数事情,所以我会浏览以前从未提及的。

所以让我们从firebase存储开始。

  1. 我们从Firebase存储中导入getDownloadUrl()。它使用的是获取我们上传到firebase存储的图像的可访问URL,因为默认情况下,在上传图像后,我们立即给它命名,但我们只能在firebase Console中访问图像,并且不是其他任何地方。

    1. 接下来是Firebase Firestore,我们导入了query()函数和where()函数,该功能将根据某些条件来查询Firestore数据库。我不会深入研究的Firestore数据库中的一个概念是“ Firestore查询”。 什么是Firestore查询?

Firestore查询是一种以特定方式从Firestore数据库中检索数据的一种方式。

  1. firestore是一个NOSQL文档数据库,该数据库存储在文档和集合中,并且可以根据指定条件从集合中检索文档。

  2. firestore查询可以根据特定条件过滤文档,根据一个或多个字段对文档进行分类,限制返回的文档数量,并仅从每个文档中检索特定字段。

  3. 查询也可以合并以创建更复杂的查询。

  4. firestore支持两种类型的查询:简单查询和复杂查询。简单查询是使用单个过滤条件的查询,而复杂的查询使用多个过滤条件或多个分类或限制条件。

  5. 可以在客户端(例如在移动或Web应用程序中)或使用云功能或其他服务器端技术在服务器端执行Firestore查询。

所以我相信我们对Firestore查询以及它们现在的工作方式有所了解,所以让我们回到我们的代码。

我们导入的另一件事是getDocs()函数,用于获取Firestore集合中的所有文档。

我们接下来要做的是为化身,用户详细信息和当前用户创建状态。之后,我初始化了我们从Firebase导入的所有功能。
接下来是我们创建并将其附加到按钮的签名功能,以登录用户,然后将其重定向到登录页面。

下一个也是最重要的是从Firebase获取用户的数据。
一旦我们初始化了getAuth()函数,我们就可以访问onAuthStateChanged()函数,该功能可以帮助我们跟踪当前是否登录的用户的身份验证状态,因此,我们可以访问“用户”对象有关当前登录的用户的所有详细信息,然后我们将用户对象传递给setCurrentUser()函数。

接下来的事情是使用Firestore查询来获取当前登录的用户的详细信息。查询函数带有两个参数:userRefwhere()函数,在我们在查询条件下传递的where函数中,它进行了。

我们希望firebase浏览集合中的所有文档,并为我们提供具有其user_id密钥等于当前登录的用户ID的文档。

之后,我们为我们的头像创建了参考。如果我们仍然记得,我们之前所做的就是用户注册并上传他的图片后立即将图像的名称更改为用户的ID。

下一个代码块检查是否存在用户,如果是,则应该使我们下载用户的头像的URL。

之后,我们使用了getDocs()函数,然后传递查询以获取用户详细信息。然后,我们使用.then()方法获取快照,我们创建了一个空数组并将其设置为user_data变量。

获取快照后,我们会自动访问docs()方法,然后循环遍历它,然后将数据推入空数阵列,然后将user_data数组传递到setUserDetails()函数中。

如果我们在snapshot.docs()方法中注意到,我们将item.data()推入数组,这是因为我们想要的数据来自Firebase的数据位于data()函数中。我们可以通过记录console.log(item)的console进行检查。

然后我们在useEffect()中调用了该函数。
哇!伙计们,我们刚刚使用Firebase构建了一个简单的全栈应用程序,真是太神奇了,感谢您在整个项目中关注我,也感谢您阅读本文,我希望很快发表另一篇文章。

结论

firebase可用于为网络和移动设备构建全堆栈应用程序,在本文中,我们演示了如何使用不同的firebase功能和服务,这只是一个简单的项目,firebase具有许多可以使用的功能构建更复杂的应用程序。查看Firebase文档以了解更多信息。