【问题标题】:Firebase authentication: how to resolve 'TypeError: Cannot read property 'getIdToken' of null' errorFirebase 身份验证:如何解决“TypeError:无法读取属性 'getIdToken' of null”错误
【发布时间】:2020-10-02 02:11:58
【问题描述】:

我是实施身份验证的新手,对如何解决我遇到的问题有些困惑。

我正在构建一个 react 应用程序,并希望登录用户能够通过 GigRegister 组件将数据提交到 firebase 数据库。但是,当我尝试提交信息时,出现以下错误:


    TypeError: Cannot read property 'getIdToken' of null

有什么想法可以解决这个问题吗?

这是登录页面的代码(登录时重定向到演出注册页面):

import React from 'react'
import Header from './Header'
import Button from '@material-ui/core/Button'
import axios from 'axios'
import {Link} from 'react-router-dom'

class Login extends React.Component {
  constructor() {
    super();
    this.state = {
      email: "",
      password: "",
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(e) {
    this.setState({
      [e.target.name]: e.target.value,
    });
  }

  handleSubmit(e) {
    console.log("submit reached");
    e.preventDefault();
    const loginData = {
      email: this.state.email,
      password: this.state.password,
    };
    axios("http://localhost:5000/gig-fort/us-central1/api/login", {
      method: "POST",
      headers: {
        "content-type": "application/json",
      },
      data: loginData,
    })
      .then((res) => {
        console.log(res.data);
        this.props.history.push("/gigregister");
      })
      .catch((err) => {
        console.error(err);
      });
  }

  render() {
    return (
      <>
        <div>
          <Header />
        </div>
        <Link to="/Homepage" style={{ textDecoration: "none" }}>
          <h1 className="login-header">Gigs this week</h1>
        </Link>
        <div className="login-main">
          <div className="login">
            <h2>Venue login</h2>
            <form onSubmit={this.handleSubmit}>
              <input
                type="text"
                name="email"
                placeholder="email"
                onChange={this.handleChange}
              />
              <br></br>
              <input
                type="password"
                name="password"
                placeholder="password"
                onChange={this.handleChange}
              />
              <div className="button">
                <Button type="submit">Submit</Button>
              </div>
            </form>
          </div>
          <Link to="/venueregister" style={{ textDecoration: "none" }}>
            <h2 style={{ color: "#b49650" }}>Register a venue</h2>
          </Link>
        </div>
      </>
    );
  }
}

export default Login;

..这是演出注册页面:


    import React from "react";
    import Header from "./Header";
    import TextField from "@material-ui/core/TextField";
    import Button from "@material-ui/core/Button";
    import axios from "axios";
    import * as firebase from 'firebase'
    
    firebase.initializeApp({
        apiKey: "",
        authDomain: "",
        databaseURL: "",
        projectId: "gig-fort",
        storageBucket: "gig-fort.appspot.com",
        messagingSenderId: "",
        appId: ""
    })
    
    
    class GigRegister extends React.Component {
      constructor() {
        super();
        this.state = {
          name: "",
          venue: "",
          time: "",
          date: "",
          genre: "",
          tickets: "",
          price: "",
        };
        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleChange = this.handleChange.bind(this);
      }
    
      handleChange(e) {
        this.setState({
          [e.target.name]: e.target.value,
        });
      }
    
      handleSubmit(e) {
        console.log("submit function reached");
        e.preventDefault();
        const gigData = {
          name: this.state.name,
          venue: this.state.venue,
          time: this.state.time,
          date: this.state.date,
          genre: this.state.genre,
          tickets: this.state.tickets,
          price: this.state.price,
        };
        
    
        firebase.auth().currentUser.getIdToken().then(function(token) {
          axios("http://localhost:5000/gig-fort/us-central1/api/createGigListing", {
            method: "POST",
            headers: {
              "content-type": "application/json",
              "Authorization": "Bearer "+token,
            },
            data: gigData,
          })
      })
          .then((res) => {
            console.log(res.data);
          })
          .catch((err) => {
            console.error(err);
          });
      }
    
    
    
      render() {
        return (
          <div className="gig-register">
            <Header />
            <h1 className="header-gigReg">Register a gig</h1>
            <form onSubmit={this.handleSubmit}>
              <TextField
                placeholder="Event name"
                defaultValue="Event name"
                id="name"
                name="name"
                onChange={this.handleChange}
              />
              <TextField
                placeholder="Venue"
                defaultValue="Venue"
                id="venue"
                name="venue"
                onChange={this.handleChange}
              />
              <TextField
                placeholder="Time"
                defaultValue="Time"
                type="time"
                label="Enter start time"
                id="time"
                name="time"
                InputLabelProps={{
                  shrink: true,
                }}
                inputProps={{
                  step: 300, // 5 min
                }}
                onChange={this.handleChange}
              />
              <TextField
                id="date"
                label="Select date"
                type="date"
                defaultValue="2017-05-24"
                InputLabelProps={{
                  shrink: true,
                }}
                onChange={(e) => {
                  this.setState({ date: e.target.value });
                }}
              />
              <TextField
                placeholder="Genre"
                defaultValue="Genre"
                id="genre"
                name="genre"
                onChange={this.handleChange}
              />
              <TextField
                placeholder="Tickets"
                defaultValue="Tickets"
                id="tickets"
                name="tickets"
                onChange={this.handleChange}
              />
              <TextField
                placeholder="Price"
                defaultValue="Price"
                id="price"
                name="price"
                onChange={this.handleChange}
              />
              <Button type="submit">Submit</Button>
            </form>
          </div>
        );
      }
    }
    
    export default GigRegister

后端功能:

app.post('/login', (req,res)=> {
    const user = {
        email: req.body.email,
        password: req.body.password
    }
    
    let errors = {}

    if(isEmpty(user.email)){
        errors.email = 'Must not be empty'
    }

    if(isEmpty(user.password)){
        errors.password = 'Must not be empty'
    }

    if(Object.keys(errors).length >0){
        return res.status(400).json(errors)
    }

    firebase.auth().signInWithEmailAndPassword(user.email, user.password)
    .then((data) => {
        return data.user.getIdToken()
    })
    .then(token => {
        return res.json({token})
    })
    .catch(err => {
        if(err.code === 'auth/wrong-password'){
            return res.status(403).json({general: 'Wrong credentials, please try again'})
        }
        return res.status(500).json({error: err.code})
    })
})

【问题讨论】:

    标签: reactjs firebase firebase-authentication


    【解决方案1】:

    您出于什么原因从后端调用signInWithEmailAndPassword?正如我所见,app.post('/login', ...) 只是验证正文,调用signInWithEmailAndPassword 并发送令牌作为响应。

    我建议将此逻辑移至客户端。在这种情况下,firebase auth 对象将具有 currentUser

    如果您不希望,您必须在客户端发出 POST 登录请求后调用 auth.signInWithCustomToken。文档:https://firebase.google.com/docs/auth/web/custom-auth#authenticate-with-firebase.

    更新:

    1。创建新文件firebase.js

    import * as firebase from 'firebase/app'
    import 'firebase/auth'
    /* if you use any other firebase modules import they here.
     * for example:
     * import "firebase/database"
     */
    
    export default function initFirebase() {
      firebase.initializeApp({
        apiKey: '',
        authDomain: '',
        databaseURL: '',
        projectId: 'gig-fort',
        storageBucket: 'gig-fort.appspot.com',
        messagingSenderId: '',
        appId: ''
      })
    }
    
    

    2。从 index.js(项目的主文件)初始化 App

    import initFirebase from 'path/to/firebase.js';
    // ...imports
    
    initFirebase();
    

    3。向Login 组件添加身份验证导入;

    import React from 'react'
    import Header from './Header'
    import Button from '@material-ui/core/Button'
    import axios from 'axios'
    import { Link } from 'react-router-dom'
    import { auth } from 'firebase/app'
    

    4。在Login 组件处替换您的提交方法

    handleSubmit(e) {
      e.preventDefault()
      const { email, password } = this.state
      const { history } = this.props
    
      auth().signInWithEmailAndPassword(email, password)
        .then((res) => {
          console.log(res)
          history.push('/gigregister')
        })
        .catch(console.error)
    }
    

    5。在GigRegister Component处替换auth import

    import { auth } from 'firebase/app'
    

    6。替换 GigRegister 组件的 auth 调用

    /* handleSubmit method */
    auth().currentUser.getIdToken().then(console.log)
    

    【讨论】:

    • 我尝试在前端移动sigInWithEmailAndPassword,但出现了同样的错误
    • @JoshSimon 是的?
    【解决方案2】:

    提示

    TypeError: Cannot read property 'getIdToken' of null

    问题

    你写的:

    firebase.auth().currentUser.getIdToken()

    编译器正在接收什么:

    null.getIdToken()

    null 没有getIdToken 方法,因此当您尝试调用该函数时,您会收到错误TypeError: Cannot read property 'getIdToken' of null

    解决方案

    您需要在代码中的某处调用firebase.auth().signInWithEmailAndPassword(email, password),然后currentUser 的详细信息将保存在浏览器的firebaseLocalStorageDB 下。

    然后你就可以正确调用firebase.auth().currentUser.getIdToken()了。

    另外,我看不出你为什么在这里使用axios。您应该使用 firebase 读/写 API,即 available here。从上到下阅读文档,您不会后悔的!

    【讨论】:

    • 感谢您的建议 - 但是我在单独的仓库中有 firebase.auth().signInWithEmailAndPassword(email, password) - 已编辑我的原始问题以包含它。
    • 检查它是否存储在您的本地存储中。在 Chrome 中:open dev tools -&gt; click Application tab -&gt; locate firebaseLocalStorageDB。如果那里有密钥,请告诉我,如果没有,您的用户没有被正确保存。
    • 我检查了,令牌存储在本地存储中,但我似乎找不到任何名为 firebaseLocalStorageDB 的东西。我感觉我需要在```.onAuthStateChanged```方法中设置用户?
    【解决方案3】:

    firebase.auth().currentUsernull。您必须在登录页面上登录 Firebase。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-29
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      • 2020-02-05
      • 1970-01-01
      • 1970-01-01
      • 2018-12-29
      相关资源
      最近更新 更多