Vamos criar a rota de login do projeto, vamos focar nessa estrutura abaixo.
.
├── src
│ └── router
│ └── index.js
No arquivo index.js
vamos adicionar o seguinte:
import { createRouter, createWebHistory } from 'vue-router'
import { getAuth, onAuthStateChanged } from 'firebase/auth'
import Login from '@/module/login/view/login.vue'
import Register from '@/module/register/view/register.vue'
import Home from '@/module/home/view/home.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
component: Home,
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/cadastro',
name: 'Register',
component: Register
}
]
})
const getCurrentUser = () => {
return new Promise((resolve, reject) => {
const removeListener = onAuthStateChanged(
getAuth(),
(user) => {
removeListener()
resolve(user)
},
reject
)
})
}
router.beforeEach(async (to, from, next) => {
const currentUser = await getCurrentUser()
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (currentUser) {
next()
} else {
alert("Você não tem acesso a essa página, por favor, autentique-e!")
next('/login')
}
} else if (
currentUser &&
(to.path === '/login' || to.path === '/cadastro'
) {
next('/')
} else {
next()
}
})
export default router
Note que agora, nosso arquivo de rota está bem mais cheio, adicionamos o import do firebase/auth
para podermos criar as validações para que o usuário não consiga acessar as telas sem estar autenticado.
Resumindo, essa parte debaixo do const router
verifica a autenticação do usuário antes de cada navegação em rotas protegidas. A função getCurrentUser
usa o método onAuthStateChanged
para monitorar a autenticação e retorna uma promessa com o usuário autenticado. No router.beforeEach
, ele verifica se a rota exige autenticação (indicada por meta.requiresAuth
). Se a rota for protegida e o usuário estiver autenticado, ele permite o acesso (next()
). Se o usuário não estiver autenticado, exibe um alerta e redireciona para /login
. Caso o usuário já esteja autenticado e tente acessar /login
ou /cadastro
, redireciona-o para a página inicial (/
), além do mais, adicionamos uma rota para a Home
e outra para o /login
.
Sobre o Home, não vou criar o arquivo, apenas coloquei ali para que possam ver como vai ficar o funcionamento para verificar se o usuário pode ou não ter acesso.
Agora, vamos partir pra criação do nosso componente de cadastro de fato, suas funções e a chamada dele, então, vamos focar nessa estrutura.
.
├── src
│ └── module
│ └── login
| └── component
| └── formlogin.vue
| └── controller
| └── loginController.js
| └── view
| └── login.vue
Arquivo formLogin.vue
.
<template>
<div class="d-flex justify-center align-center fill-height">
<v-card class="mx-auto px-6 py-8" max-width="400" min-width="300">
<v-form :disabled="controller.loading.value" :readonly="controller.loading.value">
<h1 class="text-center mb-3">Entrar</h1>
<v-text-field
class="mb-2"
label="E-mail"
variant="underlined"
clearable
:rules="[controller.regras.required, controller.regras.validEmail]"
v-model="controller.email.value"
></v-text-field>
<v-text-field
label="Senha"
placeholder="Informe sua senha"
variant="underlined"
clearable
@click:append-inner="controller.showPassword.value = !controller.showPassword.value"
:append-inner-icon="controller.showPassword.value ? 'mdi-eye' : 'mdi-eye-off'"
:type="controller.showPassword.value ? 'text' : 'password'"
:rules="[
controller.regras.required,
(v) => (v && v.length >= 6) || 'A senha deve ter no mínimo 6 caracteres'
]"
v-model="controller.password.value"
></v-text-field>
<p v-if="controller.errMsg.value" class="text-red text-center">
{{ controller.errMsg.value }}
</p>
<br />
<v-btn
color="#5865f2"
size="large"
type="submit"
variant="elevated"
block
:loading="controller.loading.value"
:disabled="
!controller.password.value ||
controller.password.value.length < 6 ||
controller.loading.value
"
@click="controller.login"
>
Entrar
</v-btn>
<br />
<v-divider class="mx-10"></v-divider>
<div class="d-flex justify-center mt-3">
<button @click="controller.signInWithGoogle">
<v-avatar :image="logoGoogle"></v-avatar>
</button>
</div>
<p class="text-center mt-5">
Ainda não possui uma conta? <a href="/cadastro">Cadastre-se</a>
</p>
</v-form>
</v-card>
</div>
</template>
<script setup>
import logoGoogle from '../../../assets/images/imagem_logo_google.png'
const { controller } = defineProps({
controller: { type: Object, required: true }
})
</script>
Arquivo loginController.js
.
import { ref } from 'vue'
import {
getAuth,
signInWithEmailAndPassword,
GoogleAuthProvider,
signInWithPopup,
} from 'firebase/auth'
import { useRouter } from 'vue-router'
const loginController = () => {
const email = ref('')
const password = ref('')
const errMsg = ref('')
const loading = ref(false)
const showPassword = ref(false)
const regras = {
required: (v) => !!v || 'Obrigatório',
validEmail: (v) => {
if (v.length > 0) {
const pattern =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return pattern.test(v) || 'E-mail inválido'
}
return true
},
const router = useRouter()
const auth = getAuth()
// Essa função é responsável por realizar o login com o firebase apenas informando o e-mail e senha
const login = async () => {
try {
loading.value = true
errMsg.value = ''
await signInWithEmailAndPassword(auth, email.value, password.value)
router.push('/')
} catch (error) {
// Note que aqui, temos um switch/case com os possíveis erros que o firebase retorna, essa variável `errMsg` está lá no `formLogin.vue` para que o usuário possa ver o erro que está retornando
switch (error.code) {
case 'auth/invalid-email':
errMsg.value = 'E-mail inválido!'
break
case 'auth/user-not-found':
errMsg.value = 'Usuário não encontrado!'
break
case 'auth/wrong-password':
errMsg.value = 'Senha incorreta!'
break
default:
errMsg.value = 'E-mail ou senha incorretos!'
break
}
} finally {
loading.value = false
}
}
// Essa função é responsável por realizar o login com o firebase utilizando o provedor Google
const signInWithGoogle = async () => {
try {
loading.value = true
const provider = new GoogleAuthProvider()
await signInWithPopup(auth, provider)
router.push('/')
} catch (error) {
alert(error)
} finally {
loading.value = false
}
}
return {
email,
password,
errMsg,
loading,
showPassword,
regras,
login,
signInWithGoogle
}
}
export { loginController }
Arquivo login.vue
.
<template>
<form-login :controller="controller" />
</template>
<script setup>
import { loginController } from '../controller/loginController'
import FormLogin from '../component/formLogin.vue'
const controller = loginController()
</script>
E com isso, finalizamos nossas telas de cadastro e login, nesse post adicionamos a rota pro /login
, adicionamos validações no router/index.js
para que o usuário só consiga acessar a home se estiver autenticado e criamos o componente do login, ao final de tudo, acessando o /login
você deverá ver uma tela semelhante a essa abaixo:
Agradeço a você que leu minha postagem até o final, espero que isso ajude muitas pessoas qye estejam com dificuldades em fazer funcionar ou que estejam começando a desenvolver. Qualquer problema que tenha, por favor, não hesite em comentar que sempre que puder irei analisar o seu problema e tentar te ajudar.
Top comments (0)