websanova / vue-auth

A simple light-weight authentication library for Vue.js
MIT License
2.36k stars 380 forks source link

get auth user from vuex #658

Closed cirolosapio closed 3 years ago

cirolosapio commented 3 years ago

with vue 3 is it possible to get the user from a vuex store?

related #205 #624

websanova commented 3 years ago

yes, there is an example in the demos.

cirolosapio commented 3 years ago

i tried this example but with vue 3 it doesn't work Vue and Vue.auth are undefined

websanova commented 3 years ago

https://github.com/websanova/vue-auth/blob/master/src/v3.js

Try something like this...

You just need to make sure you're importing the same instance...

import {useAuth as auth} from 'however you imported vue-auth already'.

....

console.log(auth().user());

auth().login();

// etc...

EDIT: And of course make sure you are using vue 3 version to being with (if not already).

cirolosapio commented 3 years ago

i've tried useAuth and it works with the vuex store but not with quasar prefetch feature :(

GMolini commented 3 years ago

How did you do it?

Ive tried using

import {useAuth as auth} from '@websanova/vue-auth';

console.log(auth())
console.log(auth().user())

and the first console.log prints

ƒ useAuth(key) {
  return Object(vue__WEBPACK_IMPORTED_MODULE_0__["inject"])(key ? key : authKey);
}

and the second one just gives an undefined

The console also gives the following message [Vue warn]: inject() can only be used inside setup() or functional components.

cirolosapio commented 3 years ago

How did you do it?

Ive tried using

import {useAuth as auth} from '@websanova/vue-auth';

console.log(auth())
console.log(auth().user())

and the first console.log prints

ƒ useAuth(key) {
  return Object(vue__WEBPACK_IMPORTED_MODULE_0__["inject"])(key ? key : authKey);
}

and the second one just gives an undefined

The console also gives the following message [Vue warn]: inject() can only be used inside setup() or functional components.

As @websanova explained you have to import the same instance

import { createAuth, useAuth } from '@websanova/vue-auth'
import driverAuthBearer from '@websanova/vue-auth/dist/drivers/auth/bearer.esm.js'
import driverHttpAxios from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js'
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js'

app.use(
  createAuth({
    plugins: {
      http: ...,
      router: ...
    },
    drivers: {
      http: driverHttpAxios,
      auth: driverAuthBearer,
      router: driverRouterVueRouter
    },
    options: {
      //
    }
  })
)

export { useAuth }
GMolini commented 3 years ago

Im not sure what Im doing wrong, but I still havent managed to do it. I was following the demo, and I have an auth.js file in the plugins folder, like this:

import { createAuth }        from '@websanova/vue-auth';
import driverAuthBearer      from '@websanova/vue-auth/dist/drivers/auth/devise.esm';
import driverHttpAxios       from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js';
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js';

export default (app) => {
  app.use(createAuth({
      plugins: {
          http: app.axios,
          router: app.router,
      },
      ...

With this authentication works, but, as I said, Im not able to import it in vuex. If I import this file, Im not able to get the useAuth, but If I declare it like you do, I don know where are you getting the app instance to be able to do the app.use(createAuth)

cirolosapio commented 3 years ago

This is the code I use

auth.js

import { createAuth, useAuth } from '@websanova/vue-auth'
import driverAuthBearer from '@websanova/vue-auth/dist/drivers/auth/bearer.esm.js'
import driverHttpAxios from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js'
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js'

export default ({ router, app }) => {
  app.use(
    createAuth({
      plugins: {
        http: ...,
        router: router
      },
      drivers: {
        http: driverHttpAxios,
        auth: driverAuthBearer,
        router: driverRouterVueRouter
      },
      options: {
        //
      }
    })
  )
}

export { useAuth }
import { useAuth } from 'boot/vue-auth'
const auth = useAuth()
GMolini commented 3 years ago

First of all, thanks for the help. I honestly do not know what the hell Im doing wrong. My plugins/auth.js

import { createAuth, useAuth }        from '@websanova/vue-auth';
import driverAuthBearer      from '@websanova/vue-auth/dist/drivers/auth/devise.esm';
import driverHttpAxios       from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js';
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js';

export default (app) => {
  app.use(createAuth({
      plugins: {
          http: app.axios,
          router: app.router,
      },
      drivers: {
          http: driverHttpAxios,
          auth: driverAuthBearer,
          router: driverRouterVueRouter,
      },
      options: {
        authRedirect: { path: '/sign_in' },
        staySignedIn: true,
        remember: true,
        stores: ['storage', 'cookie'],
        rolesKey: 'role',
        fetchUser: true,
          loginData: {
          url: `${process.env.VUE_APP_API_BASE_URL}/auth/sign_in`,
          method: 'POST',
        },      
        logoutData: {
          url: `${process.env.VUE_APP_API_BASE_URL}/auth/sign_out`,
          method: 'DELETE',
          redirect: '/sign_in',
          makeRequest: true,
        },
        fetchData: {
          url: `${process.env.VUE_APP_API_BASE_URL}/${process.env.VUE_APP_API_VERSION}/user`,
          method: 'GET',
        },
        refreshData: {
          url: `${process.env.VUE_APP_API_BASE_URL}/${process.env.VUE_APP_API_VERSION}/user`,
          method: 'GET',
        },
      }
  }));
}

export { useAuth };

Then, in a vuex store module file store/organizations.module.js

 import { useAuth } from '../plugins/auth';
 const auth = useAuth()

 console.log(useAuth)
 console.log(auth)

Those two consoles print:

ƒ useAuth(key) {
  return Object(vue__WEBPACK_IMPORTED_MODULE_0__["inject"])(key ? key : authKey);
}
undefined

And I still cant get access to the user or the check function

baka-san commented 2 years ago

@GMolini Did you ever figure this out? My setup is the same as yours in the file auth.js. I'm able to use vue-auth within my app just fine, but I can't import it elsewhere, such as in a vuex store, even with the same setup as you and @heartbeatLV

cirolosapio commented 2 years ago

@baka-san my configuration doesn't seem to work anymore for my project I rewrote the part of the library that I need

GMolini commented 2 years ago

@baka-san No I did not. I ended up using the following workaround: Im using the parseUserData callback to store the user data in vuex. then use the vuex stored data wherever I need,

import { createAuth, useAuth }        from '@websanova/vue-auth/src/v3.js';
import driverAuthBearer      from '@websanova/vue-auth/dist/drivers/auth/devise.esm';
import driverHttpAxios       from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js';
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js';
import store from '@common_src/_store/store';

export default (app) => {
  app.use(createAuth({
      plugins: {
          http: app.axios,
          router: app.router,
      },
      drivers: {
          http: driverHttpAxios,
          auth: driverAuthBearer,
          router: driverRouterVueRouter,
      },
      options: {
        authRedirect: { path: '/sign_in' },
        staySignedIn: true,
        remember: true,
        stores: ['storage', 'cookie'],
        rolesKey: 'role',
        parseUserData(data) {
          const user = data;
          store.dispatch('userModule/setUser', user)
          return user;
        },
      }
  }));
baka-san commented 2 years ago

@websanova Do you have any input on how to import and use auth outside of the vue app in a javascript file? I actually do not need to use it in vuex, so the workaround using store.dispatch won't work for me.

squareloop1 commented 2 years ago

You need to export your created auth instance. I'm doing it like this in a quasar boot file:

let auth;

export default boot(({ app, router }) => {
  auth = createAuth({ ... });
});

export { auth };

Just import from this boot file and you can use the auth instance.

lucianobosco commented 2 years ago

I'd like to share my recipe for those who are using Quasar V2 + Vite + Pinia + Axios + Laravel Passport This may need some improvements, so any advice will be appreciated.

Please note that I've created my own auth driver driverPassport for propagating tokens to any other axios request and storing tokens/user in the store.

I'm using store just for sharing tokens and user info.

auth.js Pinia store

import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useAuthStore = defineStore('auth', () => {
  const user = ref(null)
  const accessToken = ref(null)
  const refreshToken = ref(null)

  function setTokens(payload) {
    accessToken.value = payload.accessToken
    refreshToken.value = payload.refreshToken
  }

  function setUser(payload) {
    user.value = payload
  }

  return { user, accessToken, refreshToken, setTokens, setUser }
})

http.js Boot file

import { boot } from 'quasar/wrappers'
import { useAuthStore } from 'stores/auth'
import {createAuth} from '@websanova/vue-auth'
import driverHttpAxios from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js'
import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js'
import axios from 'axios'

const baseUrl = import.meta.env.VITE_API_URL

var auth = null

const api = axios.create({
  baseURL: baseUrl,
  headers: {
    common: {
      'X-Requested-With': 'XMLHttpRequest',
      'Access-Control-Allow-Origin': '*'
    }
  }
})

export default boot(({ app, router }) => {
  const store = useAuthStore()

  const passportDriver = {
    request: function (req, token) {
      // If refresh, add refresh_token to request data
      if (req.url === this.options.refreshData.url) {
        req.data = { refresh_token: this.token(this.options.refreshTokenKey) }
      }

      this.drivers.http.setHeaders.call(this, req, {
        Authorization: `Bearer ${token}`,
      })

      // Attach Authorization header to non websanova requests
      api.defaults.headers.common.Authorization = `Bearer ${token}`

      // Store tokens in Pinia
      store.setTokens({
        ...(token && { accessToken: token }),
        ...(this.token(this.options.refreshTokenKey) && { refreshToken: this.token(this.options.refreshTokenKey) })
      })
    },

    response: function (res) {
      const resData = res.data || {}

      // Store refresh_token if present
      this.token(
        this.options.refreshTokenKey,
        resData[this.options.refreshTokenKey]
      )

      // Return access_token (auto stored)
      return resData[this.options.tokenDefaultKey]
    },
  }

  auth = createAuth({
    plugins: {
      http: axios,
      router: router
    },
    drivers: {
      http: driverHttpAxios,
      auth: passportDriver,
      router: driverRouterVueRouter
    },
    options: {
      rolesKey: 'roles',
      authRedirect: { name: 'Login' },
      notFoundRedirect: {name: 'NotFound'},
      tokenDefaultKey: 'access_token',
      refreshTokenKey: 'refresh_token',
      stores: ['storage'],
      loginData: {
        url: `${baseUrl}/auth/login`,
        method: 'POST',
        redirect: '/',
        fetchUser: true,
        staySignedIn: true
      },
      fetchData: {
        url: `${baseUrl}/users/info`,
        method: 'GET',
        enabled: true
      },
      refreshData: {
        url: `${baseUrl}/auth/refresh`,
        method: 'POST',
        enabled: true,
        interval: 30
      },
      parseUserData(data) {
        // Store user in Pinia
        store.setUser(data)
        return data
      }
    }
  })
})

export { auth, api }