Только получить токен из localStorage после обновления - PullRequest
0 голосов
/ 13 октября 2019

У меня есть приложение, использующее VueJS на внешнем интерфейсе и Express / knex / postgres для внутреннего. Я использую passport, local и local_port для управления аутентификацией jwt.

Все эти стратегии для аутентификации работают, однако токен заголовка не сразу доступен в localStorage. В результате аутентифицированные ресурсы отображаются неправильно. В частности, ошибки отображения отображаются при входе в систему Twitter.

При обновлении в обоих случаях появляется маркер заголовка, и приложение ведет себя так, как ожидается.

Вот мой Api.js, который формируетоснова всех вызовов axios:

import axios from 'axios'
const token = localStorage.getItem('token')

export default () => {
  return axios.create({
    baseURL: process.env.VUE_APP_ROOT_API,
    headers: {
      'Content-Type': 'application/json',
      token: token,
    },
    validateStatus: function () {
      return true;
    }
  })
}

мы устанавливаем localStorage.token в store.js:

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import PostsService from './services/PostsService'
import ReportsService from './services/ReportsService'
import KudosService from './services/KudosService'
import ActsService from './services/ActsService'

// import SubscriptionsService from './services/SubscriptionsService'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    status: '',
    user: JSON.parse(localStorage.getItem('user')),
    token: localStorage.getItem('token') || '',
    posts: null,
    leaderboard: [],
    currentGroup: {},
    lastAct: '',
    userActs: []
  },
  mutations: {
    auth_request (state) {
      state.status = 'Signing in...'
    },
    set_user (state, user) {
      state.user = user
      localStorage.setItem('user', JSON.stringify(user))
      console.log('store sets user as: ', user)
    },
    auth_success (state) {
      state.status = 'success'
    },
    auth_error (state) {
      state.status = 'Invalid credentials'
    },
    logout (state) {
      state.status = ''
      state.user = null
      localStorage.removeItem('user')
    },
    setPosts(state, posts) {
      state.posts = posts;
    },
    setLeaderboard(state, leaderboard) {
      state.leaderboard = leaderboard
    },
    setCurrentGroup(state, group) {
      state.currentGroup = group
    },
    setKudos(state, kudos) {
      state.kudos = kudos;
    },
    setLastAct(state, lastAct) {
      state.lastAct = lastAct;
      console.log('store sets this last act: ', lastAct)
    },
    setUserActs(state, userActs) {
      state.userActs = userActs
    }
  },
  actions: {
    register ({ commit }, user) {
      return new Promise((resolve, reject) => {
        commit('auth_request')
        console.log(process.env.VUE_APP_ROOT_API)
        axios({ url: process.env.VUE_APP_ROOT_API + '/auth', data: user, method: 'POST' })
          .then(async resp => {
            const token = "Token " + resp.data.user.token
            const user = resp.data.user
            localStorage.setItem('token', token)
            axios.defaults.headers.common['token'] = token
            commit('auth_success')
            commit('set_user', user)
            resolve(resp)
          })
          .catch(err => {
            commit('auth_error', err)
            localStorage.removeItem('token')
            reject(err)
          })
      })
    },
    login ({ commit }, user) {
      return new Promise((resolve, reject) => {
        commit('auth_request')
        console.log(user);
        axios({ url: process.env.VUE_APP_ROOT_API + '/auth/login', data: user, method: 'POST' })
          .then(resp => {
            const token = "Token " + resp.data.user.token
            const user = resp.data.user
            localStorage.setItem('token', token)
            axios.defaults.headers.common['token'] = token
            // console.log(user)
            // console.log(resp)
            commit('auth_success')
            commit('set_user', user)
            resolve(resp)
          })
          .catch(err => {
            commit('auth_error')
            commit('logout')
            reject(err)
          })
      })
    },
    logout ({ commit }) {
      return new Promise((resolve) => {
        commit('logout')
        localStorage.removeItem('token')
        delete axios.defaults.headers.common['token']
        resolve()
      })
    },
    getPosts({ commit }) {
      PostsService.fetchGroupPosts()
        .then(resp => {
          console.log('this is groupPosts: ', resp);
          commit('setPosts', resp.data);
        });
    },
    updateLeaderboard({ commit }, group) {
      ReportsService.getLeaderboard(group.id)
        .then(resp => {
          commit('setLeaderboard', resp);
        });
    },
    getKudos({ commit }) {
      KudosService.fetchKudos()
        .then(resp => {
          commit('setKudos', resp.data);
        });
    },
    async getLastAct({ commit }) {
      await ActsService.fetchLastAct()
        .then(resp => {
          console.log('this is the last act: ', resp);
          commit('setLastAct', resp.data[0]);
        });
    },
    async getUserActs({ commit }) {
      ActsService.fetchCurrentUserActs()
        .then(resp => {
          commit('setUserActs', resp.data);
        });
    },
    setUser({ commit }, user ) {
      const token = "Token " + user.token
      localStorage.setItem('token', token)
      axios.defaults.headers.common['token'] = token
      commit('set_user', user )
    }
  },
  getters: {
    isAuthenticated: state => !!state.user,
    authStatus: state => state.status,
    user: state => state.user,
    token: state => state.token,
    posts: state => {
      return state.posts;
    },
    kudos: state => {
      return state.kudos;
    },
    leaderboard: state => {
      return state.leaderboard;
    },
    currentGroup: state => {
      return state.currentGroup;
    },
    lastAct: state => {
      return state.lastAct;
    },
    userActs: state => {
      return state.userActs
    }
  }
})

вот конфигурация паспорта со стороны экспресса:

const passport = require('passport');
const LocalStrategy = require('passport-local');
const TwitterStrategy = require('passport-twitter').Strategy
const authHelpers = require('../auth/helpers');
var port = process.env.PORT || 8000;
const User = require('../models/User');

var trustProxy = false;
if (process.env.DYNO) {
  // Apps on heroku are behind a trusted proxy
  trustProxy = true;
}

passport.use(new LocalStrategy({
  usernameField: 'user[email]',
  passwordField: 'user[password]',
}, async (email, password, done) => {
  const user = await User.query().where('email', email );
  if (user && user.length === 1 && authHelpers.comparePass(password, user[0].password)) {
    return done(null, user[0]);
  } else {
    return done(null, false, { errors: { 'email or password': 'is invalid' } });
  }
}));

passport.use(new TwitterStrategy({
  consumerKey: process.env.TWITTER_CONSUMER_KEY,
  consumerSecret: process.env.TWITTER_SECRET_KEY,
  callbackURL: process.env.TWITTER_CALLBACK_URL, //this will need to be dealt with
  proxy: trustProxy
  }, async function(token, tokenSecret, profile, done) {
    console.log('profile is: ', profile._json.id_str)
    let user = await User.query().findOne({twitter_id: profile._json.id_str})
    console.log('retrieved user')
    if (user) {
      // todo: update user with twitter profile
      return done(null, user);
    } else {
        user = await authHelpers.createTwitterUser(profile);
        console.log("The User from createTwitterUser is " + user);
        return done(null, user);
    }
}));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

и мой файл маршрутов:

const express = require('express');
const User = require('../models/User');
const auth = require('../middlewares/authenticate');
const passport = require('passport');
const authHelpers = require('../auth/helpers')

let router = express.Router();

router.get('/currentUser', auth.required, async (req, res) => {
  const userId = req.user.id;
  console.log(req.user);
  const user = await User.query().where('id', userId );
  if (user && user.length === 1) {
    res.json({
      user: {
        id: user[0].id,
        email: user[0].email,
        username: user[0].username
      }
    });
  } else {
    res.status(404).json({});
  }
});

//POST new user route (optional, everyone has access)
router.post('/', auth.optional, async (req, res, next) => {
  const { body: { user } } = req;
  console.log("this is the request.body sent to the post route: ", req.body);

  if (!user.email) {
    return res.status(422).json({
      errors: {
        email: 'is required',
      },
    });
  }

  if (!user.password) {
    return res.status(422).json({
      errors: {
        password: 'is required',
      },
    });
  }

  const finalUser = await authHelpers.createUser(req, res);
  console.log("The finalUser from createUser is " + finalUser);

  res.json({ user: authHelpers.toAuthJSON(finalUser) });
});

//POST login route (optional, everyone has access)
router.post('/login', auth.optional, (req, res, next) => {
  const { body: { user } } = req;

  if (!user.email) {
    return res.status(422).json({
      errors: {
        email: 'is required',
      },
    });
  }

  if (!user.password) {
    return res.status(422).json({
      errors: {
        password: 'is required',
      },
    });
  }

  return passport.authenticate('local', { session: false }, (err, passportUser, info) => {
    if (err) {
      return next(err);
    }

    if (passportUser) { // user successfully authenticated
      return res.json({ user: authHelpers.toAuthJSON(passportUser) });
    } else { // user failed to authenticate
      err = new Error('Incorrect credentials');
      err.status = 401;
      next(err);
    }
  })(req, res, next);
});

router.get('/twitter',
  passport.authenticate('twitter')
);

router.get('/twitter/callback', 
  passport.authenticate('twitter', { failureRedirect: process.env.VUE_LOGIN_URL}),
  function(req, res) {
    // Successful authentication, redirect home.
    const user = JSON.stringify(authHelpers.toAuthJSON(req.user));
    console.log('hitting the callback route sending stringified user: ', user);
    res.redirect(process.env.VUE_HOME_URL + '?user=' + user);
  });

module.exports = router;
...