React:如何从登录页面到重定向页面进行身份验证?

时间:2020-10-01 10:29:46

标签: reactjs firebase authentication firebase-authentication

在我的React项目中,用户登录,然后重定向到页面'/registergig'。这是一个受保护的页面,只有登录的用户才可以访问。

在“注册演出”页面上,要求用户输入发布到Firebase数据库的文本数据。但是,当我尝试提交数据时,返回403错误: index.js:1 Error: Request failed with status code 403

我刚开始实施auth,这有点令人困惑,因此如何使'/registergig'成为受保护的页面,允许用户提交信息?

这是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'

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;

这里是GigRegister 组件,它接收用户信息:

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";

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,
    };
    axios("http://localhost:5000/gig-fort/us-central1/api/createGigListing", {
      method: "POST",
      headers: {
        "content-type": "application/json",
      },
      data: gigData,
    })
      .then((res) => {
        console.log(res.data);
      })
      .catch((err) => {
        console.error(err);
      });
  }

  setDate() {}

  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

...这是express / firebase函数:

const FBAuth = (req, res, next) => {
    let idToken;
    if(req.headers.authorization && req.headers.authorization.startsWith('Bearer ')){
        idToken = req.headers.authorization.split('Bearer ')[1]
    } else {
        console.error('No token found')
        return res.status(403).json({error: 'Unauthorized'})
    }

    admin.auth().verifyIdToken(idToken)
    .then(decodedToken => {
        req.user = decodedToken;
        return db.collection('users')
        .where('userId', '==',req.user.uid)
        .limit(1)
        .get()
    })
    .then(data =>{
        req.user.venueName = data.docs[0].data().venueName;
        return next();
    })
    .catch(err => {
        console.error('Error while verifying token', err)
        return res.status(403).json(err)
    })
}


app.post('/createGigListing', FBAuth, (req,res) => {
    const newGig = {
        venueName: req.user.venueName,
        name: req.body.name,
        time: req.body.time,
        price: req.body.price,
        genre: req.body.genre,
        tickets: req.body.tickets,
        date: req.body.date
    }
    db
    .collection('gig-listing')
    .add(newGig)
    .then(doc => {
        res.json({message: `document ${doc.id} created successfully`})
    })
    .catch(err =>{
        res.status(500).json({error: 'something went wrong'})
        console.error(err)
    })
})

1 个答案:

答案 0 :(得分:1)

您的Cloud Functions代码期望其中包含Authorization令牌的Bearer标头,但是您的客户端代码未在此调用中传递该标头:

axios("http://localhost:5000/gig-fort/us-central1/api/createGigListing", {
  method: "POST",
  headers: {
    "content-type": "application/json",
  },
  data: gigData,
})

因此,您必须在此处添加标头,并传递ID令牌:

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,
    })

});

我大致基于functions-samples回购中的this code