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
accessTokenna 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
userna 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