简体   繁体   中英

setting cookie with jwt token in react client using express backend

I am trying to set a cookie in the browser for authentication. When using POSTMAN the cookie is returned with no problem, as well as any other response I send. However in the react app, it is failing to fetch. It seems to be complaining about CORS, in particular this line of code being set to : res.header("Access-Control-Allow-Origin", " ");

I have an app.js file in which I configure CORS and all of my routes, and my basic fetches work perfectly. When attempting to set a cookie in a route file, it fails to fetch. Here is the app.js file

 //packages var bodyParser = require ('body-parser') var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var cors = require('cors'); var mysql = require('mysql'); //routes const accountRouter = require('./routes/account'); //express app var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); app.use(cors()); app.use(bodyParser.json()); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); //use routes app.use('/account', accountRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // Tells Express to allows data to be sent across different origins // required by CORS policy app.use(function (req, res, next) { res.header("Access-Control-Allow-Origin", "localhost:3001"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;

Here is my route file that checks for an existing email, then verifies the password. After verifying the password I generate the token, and send it as a cookie. Again, in POSTMAN this functions fine.

 var express = require('express'); var router = express.Router(); var bcryptjs = require('bcryptjs') var cookieParser = require('cookie-parser'); var jwt = require('jsonwebtoken'); var pool = require('../database/accountsdb'); const saltRounds = 12; function authenticate(req,res) { //Check for existing email //Create DB Connection pool.getConnection(function(err, connection){ if(err) { connection.release(); res.json({"code": 100, "status": "Error in database connection"}); return; } //Variables and SQL let emailSQL ='SELECT intAccountID FROM accountdetails where strEmail = ?'; let email = req.body.email; connection.query(emailSQL, email, function(err, result){ if(!err){ //check if matching row was found if(result.length>0){ //Get password let accountID = result[0].intAccountID; let accountSQL = "SELECT strPassword, intAccountID FROM accounts WHERE intAccountID = ?"; connection.query(accountSQL, accountID, function(err, result){ if(!err){ //get password let hashed = result[0].strPassword; //get ID let ID = result[0].intAccountID; //compare passwords bcryptjs.compare(req.body.password, hashed, function(err, result){ if(!err){ if(result== true){ let payload = { check: true, ID: ID }; //generate token let token = jwt.sign(payload, process.env.TOKEN_SECRET, { expiresIn: 1440 //24 hours }); //TESTING EXPIRE //TESTING EXPIRE let expiration= 1000; //return token cookie //NEED TO SEND COOKIE !!!!!!!!!!!!!!!!!!!!! res.cookie('token', token, { expires: new Date(Date.now() + expiration), httpOnly: true, }); }else{ //return failed res.json({ message: 'Invalid Email or Password' }); } }else{ res.json({err: err}); } }) }else{ //return error res.json({err:err}); } }) }else{ //return failed res.json({ message: 'Invalid Email or Password' }); } }else{ connection.release(); res.json({err}); return; } connection.release(); }) connection.on('error', function(err){ res.json({"code": 100, "status": "Error in database connection"}); }) }) }; router.post('/authenticate', function(req, res){ authenticate(req, res); }); module.exports = router;

Here is the react component to validate that a valid email was entered, the password is not empty, and the the API call to POST the data to express for authentication.

 // Dependencies import React, {Component} from 'react'; import validator from 'validator'; class Login extends Component{ constructor(props){ super(props); this.state = { email: '', password:'' } this.handleSubmit = this.handleSubmit.bind(this); } handleChangeEmail = (event) => { this.setState({email: event.target.value}); } handleChangePass = (event) => { this.setState({password: event.target.value}); } verifyInput(data){ //Validate Email if(validator.isEmail(data.email) == false){ return false; } } handleSubmit(event){ let data = { email: this.state.email, password: this.state.password } let isValid= this.verifyInput(data) if(isValid == false){ alert("Please enter a valid email address") event.preventDefault(); }else{ //api parameters to register user const url ='http://localhost:3001/account/authenticate' const options = { method:'POST', headers:{ 'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8' }, body: JSON.stringify(data) } //call api fetch(url, options) .then(response=> { console.log(response.headers) }).catch(error=>console.log(error)) } } render (){ return( <div className="register"> <form onSubmit={this.handleSubmit}> <table> <tbody> <tr> <td>Email:</td> <td> <input type="email" value={this.state.email} onChange={this.handleChangeEmail} /> </td> </tr> <tr> <td>Password:</td> <td> <input type="text" value={this.state.password} onChange={this.handleChangePass}></input> </td> </tr> <tr> <td> <input disabled={false} type="submit" value="Submit" onSubmit={(e) => this.handleSubmit(e)}/> </td> </tr> </tbody> </table> </form> </div> ) } } export default Login;

What do I do in order to fix this issue? The react client is on localhost:3000 and express on localhost:3001

Try installing http-proxy-middleware using npm or Yarn, then create src/setupProxy.js and place the following contents in it:

const proxy = require('http-proxy-middleware');
module.exports = function(app) {
  app.use(
    '/api',
    proxy({
      target: 'http://localhost:3001',
      changeOrigin: true,
    })
  );
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM