christianmalek / vuex-rest-api

A utility to simplify the use of REST APIs with Vuex
http://vuex-rest-api.org
MIT License
382 stars 48 forks source link

using with websanova for making certain actions auth-only #61

Closed vesper8 closed 6 years ago

vesper8 commented 6 years ago

I have websanova/vue-auth working as far as logging in. On the backend I use Laravel and JWT

This works great.

Now I want to make it so that certain actions, such as the action of adding a new post, can only be performed if the user is authenticated

I tried to follow what the readme says but I'm stuck and I think I'm not fully understanding.

This is what my post module looks like before

import Vue from 'vue';

import Vapi from 'vuex-rest-api';

const post = new Vapi({
  axios: Vue.axios,
  baseURL: '/api',
  state: {
    post: {
      id: 0,
      name: '',
    },
  },
})
  .get({
    action: 'getPost',
    property: 'post',
    path: ({ postId, eid }) => `/post?postId=${postId}`,
  })
  .post({
    action: 'addPost',
    property: 'post',
    path: ({ postId, name }) => `/post?name=${name}`,
  })
  .getStore();

export default post;

and now I'm trying to add websanova

import Vue from 'vue';

import Vapi from 'vuex-rest-api';

const post = new Vapi({
  axios: Vue.axios,
  baseURL: '/api',
  state: {
    post: {
      id: 0,
      name: '',
    },
  },
})
  .get({
    action: 'getPost',
    property: 'post',
    path: ({ postId, eid }) => `/post?postId=${postId}`,
  })
  .post({
    action: 'addPost',
    property: 'post',
    path: ({ postId, name }) => `/post?name=${name}`,
  })
  .getStore();

export default post;

I tested the addPost action. It works, but on the Laravel end I am not able to detect the authenticated user, so I don't think the bearer authorization headers are being passed. I must be missing something

in my main.js I define the VueAuth section like so

Vue.router = router;

Vue.use(VueAxios, axios);
Vue.use(VueAuth, {
  auth: require('@websanova/vue-auth/drivers/auth/bearer.js'),
  http: require('@websanova/vue-auth/drivers/http/axios.1.x.js'),
  router: require('@websanova/vue-auth/drivers/router/vue-router.2.x.js'),
  loginData: {
    url: '/api/auth/login',
    method: 'POST',
    redirect: '/',
    fetchUser: false,
  },
  registerData: {
    url: '/api/auth/register',
    method: 'POST',
    redirect: '/',
    fetchUser: false,
  },
  logoutData: {
    url: '/api/auth/logout',
    method: 'GET',
    redirect: '/login',
    makeRequest: true,
  },
  refreshData: {
    url: '/api/auth/refresh',
    method: 'GET',
    enabled: false,
    interval: 30,
    error() {
      window.localStorage.clear();
      window.location = `${URL}login`;
    },
  },
  fetchData: {
    url: '/api/auth/user',
    method: 'GET',
    enabled: true,
  },
});

Could the problem be that I import my store above the VueAuth definition?

import store from './vuex/store';

It's as part of my store.js that I define all my vapi modules

christianmalek commented 6 years ago

Could you please check if Vue.axios is defined on the following line?

import Vue from 'vue';
import Vapi from 'vuex-rest-api';

// test here
console.log(Vue.axios)

const post = new Vapi({
  axios: Vue.axios,
  baseURL: '/api',
  state: {
    post: {
      id: 0,
      name: '',
// ...code shortened
vesper8 commented 6 years ago

Nice catch.. it was undefined. I guess this makes sense since I was running the auth-related code below where I imported the store

I have abstracted my auth-related code to a auth.js now, which looks like

/* eslint-disable global-require */
import Vue from 'vue';

import axios from 'axios';
import VueAxios from 'vue-axios';
import VueAuth from '@websanova/vue-auth';

import router from './router';

// axios.defaults.baseURL = '/api';

Vue.router = router;

Vue.use(VueAxios, axios);
Vue.use(VueAuth, {
  auth: require('@websanova/vue-auth/drivers/auth/bearer.js'),
  http: require('@websanova/vue-auth/drivers/http/axios.1.x.js'),
  router: require('@websanova/vue-auth/drivers/router/vue-router.2.x.js'),
  loginData: {
    url: '/api/auth/login',
    method: 'POST',
    redirect: '/',
    fetchUser: false,
  },
  registerData: {
    url: '/api/auth/register',
    method: 'POST',
    redirect: '/',
    fetchUser: false,
  },
  logoutData: {
    url: '/api/auth/logout',
    method: 'GET',
    redirect: '/login',
    makeRequest: true,
  },
  refreshData: {
    url: '/api/auth/refresh',
    method: 'GET',
    enabled: false,
    interval: 30,
    error() {
      window.localStorage.clear();
      window.location = `${URL}login`;
    },
  },
  fetchData: {
    url: '/api/auth/user',
    method: 'GET',
    enabled: true,
  },
});

and I moved that import above the import for store.js

now when I do console.log(Vue.axios) I get

ƒ wrap() {
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; i++) {
      args[i] = arguments[i];
    }
    return fn.apply(thisArg, args);
  }

I'm not sure if this is what it's supposed to say.

In any case.. I just realized that the main reason this wasn't working at all is because I hadn't added the jwt.auth middleware on my addPost api route on the laravel backend

Now that I've added it.. it works

However.. I am also realizing that I neither need to change the order of the auth / store nor do I need to add the line

axios: Vue.axios

To my vapi module

I've now removed that line and put things back the way they were before and as long as I am logged in on the vue-cli side, the authorization header is always passed to all of my vapi api calls and I am able to validate the user on the laravel side

So.. I guess this just works out of the box.. and now I wonder what is the point of adding any additional configuration as mentioned in this package's readme? What is that for? Is it for added functionality that I am now currently using?

christianmalek commented 6 years ago

The simple explanation is: I used it with Vue.axios and it worked. I didn't try to use it with the global axios instance. If this is working wihout it all the better. PRs are welcome if you want to improve the README. :)

christianmalek commented 6 years ago

So.. I guess this just works out of the box.. and now I wonder what is the point of adding any additional configuration as mentioned in this package's readme? What is that for? Is it for added functionality that I am now currently using?

You could use multiple Vapi stores with different axios instances. If you don't pass an instance it will default to the global axios instance which apparantly vue-auth is using.

christianmalek commented 6 years ago

I'll close this. If you have further questions feel free to open a new issue or comment here again.