npm.io
3.2.0 • Published 11 months ago

@bildvitta/quasar-app-extension-hub

Licence
MIT
Version
3.2.0
Deps
3
Size
100 kB
Vulns
0
Weekly
0
Stars
2

Quasar App Extension Hub

Adiciona integração com o Hub de autenticação. Compatível com quasar v1 quasar v2.

Para fazer o controle de estado da aplicação, esta extensão aceita pinia e vuex, dependendo de qual versão do quasar estiver utilizando:

  • Quasar v1:
    • [] pinia
    • vuex
  • Quasar v2:
    • pinia
    • vuex

Instalação

Entre no diretório do seu projeto Quasar e execute o comando:

$ quasar ext add @bildvitta/hub

Após isto, será gerado um arquivo hub.config.js com a seguinte configuração:

module.exports = {
  hasAsteroid: true, // usado caso tenha extensão @bildvitta/asteroid instalada na aplicação
  forbiddenRouteName: 'Forbidden', // usado para definir o nome da rota da pagina de erro 404 (Forbidden)
  storeAdapter: 'vuex', // usado para definir qual store esta utilizando na aplicação "vuex" ou "pinia"
  development: { // ambiente de desenvolvimento
    localhost: {
      useAutomaticLogin: true, // usado para definir se o login automático sera feito
      environment: 'development', // flag para definir o ambiente
      url: '' // url do ambiente a ser acessado
    },

    preview: {
      useAutomaticLogin: true, // usado para definir se o login automático sera feito
      environment: 'temporary', // flag para definir o ambiente
      url: '' // url do ambiente a ser acessado
    }
  },
  defaultFilters: {} // usado para deixar dinâmico e personalizável o filtro padrão salvo no storage.
}

A chave defaultFilters, serve como referência para salvar no storage quais serão os filtros padrões e da onde será pego a primeira opção. Ex:

{
  properties: 'property'
}

A chave (properties) é a listagem de referência que será utilizada para pegar a primeira opção. Já o valor (property), é como vamos salvar no storage o primeiro item encontrado dentro de properties. Sendo assim, vamos salvar no storage property: property: <valor-da-primeira-opção-de-properties>.

Lembrando que este arquivo não é obrigatório sendo possível utilizar somente para alterar configurações especificas como por exemplo usar apenas para alterar o storeAdapter.

Variáveis de ambiente:

Nome Tipo Obrigatório
ME_VERSION 1|2 Sim
ENVIRONMENT production|development|temporary Sim

Dica

O path 'hub' quando utilizado para importação import { ... } from 'hub/vuex' ou import { ... } from 'hub/pinia' é criado via alias, então é perdido todo o autocomplete/intellisense do vscode, para contornar isto, dentro do jsconfig.json, adicione:

pinia:

"compilerOptions": {
  "baseUrl": ".",
  "paths": {
    "hub/pinia": ["node_modules/@bildvitta/quasar-app-extension-hub/src/globals/pinia/index.js"]
  }
}

vuex:

"compilerOptions": {
  "baseUrl": ".",
  "paths": {
    "hub/vuex": ["node_modules/@bildvitta/quasar-app-extension-hub/src/globals/vuex/index.js"]
  }
}

Pronto, agora ao importar vai aparecer todas possíveis opções a serem importadas, e o JSDOC irá funcionar.

Usando com Vuex

Por padrão a store de controle de estado é utilizando vuex, como estamos dando compatibilidade tanto para pinia quando para vuex, não existem mutations dentro da nossa store, uma vez que mutations não existem no pinia, por conta disto quando utilizar vuex é necessário desativar o modo strict, caso contrario vai aparecer vários erros de alteração de state fora de mutations, entre no index.js do store e desabilite, por exemplo:

export default store(function (/* { ssrContext } */) {
  const Store = createStore({
    modules: {
      // example
    },

    strict: false // Aqui desativamos o strict!!!
  })

  return Store
})

Pronto, agora podemos utilizar nossa extensão com vuex.

Usando store do vuex:

import { mapState } from 'vuex'

...mapState('hub', ['user', 'accessToken'])

// ou

// esta forma de utilizar é a MENOS recomendada
this.$store.state.hub.user
this.$store.state.hub.accessToken

Usando com Pinia

Caso não exista o arquivo hub.config.js, crie um na raiz da aplicação e adicione a seguinte configuração:

// hub.config.js
module.exports = {
  storeAdapter: 'pinia'
}

Usando store do pinia:

import { hubStore } from 'hub/pinia'

const hub = hubStore()

hub.user // retorna o usuário caso exista
hub.accessToken // retorna o accessToken caso existe, e assim por diante...

// ou

// esta forma de utilizar é a MENOS recomendada
this.$piniaStore.hub.user
this.$piniaStore.hub.accessToken

Para mais detalhes de como utilizar uma store do Pinia, clique aqui.

Estrutura da store (pinia ou vuex)

A store gerada contém a seguinte estrutura abaixo, independente se utilizar pinia ou vuex:

State
  • accessToken
  • user
Getters
  • hasAccessToken
  • hasUser
  • userPermissions
Actions
  • clear
  • callback
  • getUser
  • login
  • logout
  • refresh
  • getUserMeURL
  • setAccessToken

Validação das rotas

Para a validação das rotas, será necessário adicionar no objeto correspondente a rota o seguinte trecho de código: meta: { requiresAuth: true }.

Ele poderá ser adicionado diretamente na raiz, assim atribuindo a validação nas rotas filhas.

Endpoints

Esta extensão comunica-se apenas com a aplicação servidor diretamente ligada ao projeto, que deve possuir os seguintes endpoints:

Endpoint Método Parâmetros Retorno Descrição
/users/me?version={process.env.ME_VERSION} GET { user: { ... } } Busca os dados do usuário autenticado.
/auth/callback GET code e state: Chaves do Hub. { accessToken: '...' } Irá retornar o JWT.
/auth/login GET url: Endereço de callback. { loginUrl: '...' } Busca o endereço de autenticação.
/auth/logout GET url: Endereço de callback. { logoutUrl: '...' } Busca o endereço de desconexão.
/auth/refresh GET { accessToken: '...' } Irá retornar um novo JWT.

Eventos

É possível solicitar o accessToken e user através do window.postMessage (muito útil para utilizar com PWA).

  • solicitar accessToken na aplicação:

    // aqui você solicita o accessToken
    window.postMessage({ type: 'requestAccessToken' })
    
    // aqui você recebe a solicitação do accessToken
    window.addEventListener('message', ({ data }) => {
      data.type // responseAccessToken
      data.accessToken // accessToken atual
    })
  • solicitar user na aplicação:

    // aqui você solicita o user
    window.postMessage({ type: 'requestUser' })
    
    // aqui você recebe a solicitação do user
    window.addEventListener('message', ({ data }) => {
      data.type // responseUser
      data.user // user atual
    })
  • Evento que retorna toda vez que o user é atualizado (users/me):

    
    window.addEventListener('message', ({ data }) => {
      data.type // updateUser
      data.user // user atualizado
    })
  • Evento que retorna toda vez que o accessToken é atualizado:

    window.addEventListener('message', ({ data }) => {
      data.type // updateAccessToken
      data.accessToken // token atualizado
    })

Composables

É possível importar o composable useCan e useAppCan para utilizar com Composition API, existem 2 opções, para o pinia e para o vuex:

import { useCan, useAppCan } from 'hub/vuex'

const { can, canAny } = useCan()

const {
  can,
  canList,
  canCreate,
  canByPermission,
  canEdit,
  canDelete,
  canShow
} = useAppCan()
import { useCan } from 'hub/pinia'

const { can, canAny, useAppCan } = useCan()

const {
  can,
  canList,
  canCreate,
  canByPermission,
  canEdit,
  canDelete,
  canShow
} = useAppCan()

Os métodos de permissionamento, irão olhar para a chave companyPermissions dentro do user (recebido do /me). A chave se trata de um objeto no qual retorna a key é o UUID da company em questão e seu valor é um array com a lista de permissões do usuário naquela company. Ex:

companyPermissions = {
  'ebde8a05-fe11-44ad-9b3a-39dee841c83b': [
    'permission.list',
    'otherPermission.list'
  ]
}

As permissões internamente são convertidas para camelCase, tanto a action quanto a entidade em questão, então para utilização do composable podemos utilizar a entity para facilitar o uso. Exemplo de uso:

can('otherPermission', { action: 'viewContract' })

Funções globais

Esta extensão também verifica se o usuário possui ou não permissões para visualizar o conteúdo com a função $can A função verifica no retorno do usuário logado, se ele possui ou não privilégios atrelados à chamada do /me salvo na storage

$can('permissionName.permissionAction', 'id')

permissionName = Nome da permissão em questão permissionAction = Ação da permissão id = Chave única da entidade (não obrigatório), necessário quando existe a verificação de um item especifico

ex.: $can('realState.create') -> Verifica se o usuário possui permissões de criação de empreendimento ex. 2: $can('realState.show, realStateId)-> Verifica se o usuário possui permissão para ver o empreendimento de idrealStateId`

Obs.: Caso o usuário tenha permissões de verificar todas as entidades, ele terá um wildcard *. Obs. 2: Essa função também verifica se o usuário é superuser, caso positivo, ira retornar sempre true

Observação importante: Não existe uma função global para o composable useAppCan, para isto, quando utilizado em options api, continue utilizando o composable, exemplo:

import { useAppCan } from 'hub/vuex'

export default {
  name: 'XPTO',

  data () {
    permission: useAppCan()
  },

  created () {
    ...

    if (this.permission.canList('xpto')) ...
  }
}

Contribuindo

Com este repositório em sua máquina, basta instalar a extensão apontando o diretório local de dentro de uma aplicação Quasar, por exemplo:

$ npm i -D file://../quasar-app-extension-hub

Ainda que dispensável para esta extensão, você pode invocar o arquivo de instalação executando o comando:

$ quasar ext invoke @bildvitta/hub