# AUTH API Firebase (option api)
Configurar auth en nuestra aplicación de Vue.
# Reglas de Seguridad
{
"rules": {
"tareas-api": {
".read": "auth != null",
".write": "auth != null"
}
}
}
Al final de esta sección:
{
"rules": {
"tareas-api": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
# cargarLocalStorage
Pasar la información del App.vue
a Home.vue
methods: {
...mapActions(['setTareas', 'cargarLocalStorage']),
},
created(){
this.cargarLocalStorage()
}
# Ruta Registro
const routes = [
{
path: '/registro',
name: 'Registro',
component: () => import(/* webpackChunkName: "about" */ '../views/Registro.vue')
}
]
# Registro.vue
<template>
<h1 class="my-5">Registro</h1>
<form>
<input
type="email"
placeholder="email"
class="form-control my-2"
v-model.trim="email"
>
<input
type="password"
placeholder="password"
class="form-control my-2"
v-model.trim="pass1"
>
<input
type="password"
placeholder="password"
class="form-control my-2"
v-model.trim="pass2"
>
<button
type="submit"
class="btn btn-primary"
:disabled="bloquear"
>
Registro
</button>
</form>
</template>
<script>
export default {
data() {
return {
email: '',
pass1: '',
pass2: ''
}
},
computed: {
bloquear(){
if(!this.email.includes('@')){
return true
}
if(this.pass1 === this.pass2 && this.pass1 !== '' && this.pass1.length > 5){
return false
}
return true
}
}
}
</script>
# Activar Registro Firebase
Dentro de la administración de Firebase activar "Sign-in method" => "correo electrónico/contraseña"
# Registrar Firebase
https://firebase.google.com/docs/reference/rest/auth (opens new window)
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
export default createStore({
state: {
user: null
},
mutations: {
setUser(state, payload) {
state.user = payload
},
},
actions: {
async registrarUsuario({ commit }, user) {
try {
const res = await fetch(`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]`, {
method: 'POST',
body: JSON.stringify({
email: user.email,
password: user.password,
returnSecureToken: true
})
})
const dataDB = await res.json()
console.log(dataDB)
if (dataDB.error) {
return console.log(dataDB.error)
}
commit('setUser', dataDB)
router.push('/')
} catch (error) {
console.log(error)
}
}
})
<form
@submit.prevent="registrarUsuario({email: email, password: pass1}"
>
import {mapActions} from 'vuex'
export default {
methods: {
...mapActions(['registrarUsuario'])
}
}
# Ingreso.vue
{
path: '/ingreso',
name: 'Ingreso',
component: () => import(/* webpackChunkName: "about" */ '../views/Ingreso.vue')
}
<template>
<h1 class="my-5">Registro</h1>
<form @submit.prevent="ingresoUsuario({email: email, password: pass1})">
<input
type="email"
placeholder="email"
class="form-control my-2"
v-model.trim="email"
>
<input
type="password"
placeholder="password"
class="form-control my-2"
v-model.trim="pass1"
>
<button
type="submit"
class="btn btn-primary"
:disabled="bloquear"
>
Ingresar
</button>
</form>
</template>
<script>
import {mapActions} from 'vuex'
export default {
data() {
return {
email: '',
pass1: '',
}
},
computed: {
bloquear(){
if(!this.email.includes('@')){
return true
}
if(this.pass1.length > 5){
return false
}
return true
}
},
methods: {
...mapActions(['ingresoUsuario'])
}
}
</script>
vuex
async ingresoUsuario({ commit }, usuario) {
console.log(usuario)
},
# ingresoUsuario Firebase
https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]
async ingresoUsuario({ commit }, usuario) {
try {
const res = await fetch(`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]`, {
method: 'POST',
body: JSON.stringify({
email: usuario.email,
password: usuario.password,
returnSecureToken: true
})
})
const dataDB = await res.json()
console.log(dataDB)
if (dataDB.error) {
return console.log(dataDB.error)
}
commit('setUser', dataDB)
router.push('/')
} catch (error) {
console.log(error)
}
},
# Leer doc con token
https://firebase.google.com/docs/database/rest/auth#authenticate_with_an_id_token (opens new window)
"https://<DATABASE_NAME>.firebaseio.com/users/ada/name.json?auth=<ID_TOKEN>"
await fetch(`<DATABASE_NAME>.firebaseio.com/tareas-api.json?auth=${state.user.idToken}`)
async cargarLocalStorage({ commit, state }) {
try {
const res = await fetch(`<DATABASE_NAME>.firebaseio.com/tareas-api.json?auth=${state.user.idToken}`)
const db = await res.json()
const arrayDatos = []
for (let id in db){
// console.log(id)
// console.log(db[id])
arrayDatos.push(db[id])
}
console.log(arrayDatos)
commit('cargar', arrayDatos)
} catch (error) {
console.log(error)
}
},
# Tareas UID
https://firebase.google.com/docs/database/security (opens new window)
{
"rules": {
"tareas-api": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
async cargarLocalStorage({ commit, state }) {
console.log('cargarLocalStorage', state)
try {
const res = await fetch(`https://<DATABASE_NAME>/tareas-api/${state.user.localId}.json?auth=${state.user.idToken}`)
const db = await res.json()
const arrayDatos = []
for (let id in db){
arrayDatos.push(db[id])
}
console.log(arrayDatos)
commit('cargar', arrayDatos)
} catch (error) {
console.log(error)
}
},
async setTareas({ commit, state }, tarea) {
console.log('setTareas', state)
try {
const res = await fetch(`https://<DATABASE_NAME>/tareas-api/${state.user.localId}/${tarea.id}.json?auth=${state.user.idToken}`, {
method: 'PUT',
body: JSON.stringify(tarea)
})
const db = await res.json()
console.log(db)
commit('set', tarea)
} catch (error) {
console.log(error)
}
},
# Getters
getters: {
userAutenticado(state) {
return !!state.user
}
},
# Navbar
<template>
<div class="navbar navbar-dark bg-dark">
<router-link to="/" class="navbar-brand">
Formularios
</router-link>
<div class="d-flex">
<router-link
class="btn btn-dark"
to="/"
v-if="userAutenticado"
>
Tareas
</router-link>
<button
class="btn btn-dark"
v-if="userAutenticado"
>
Cerrar Sesión
</button>
<router-link
class="btn btn-dark"
to="/registro"
v-if="!userAutenticado"
>
Registro
</router-link>
<router-link
class="btn btn-dark"
to="/ingreso"
v-if="!userAutenticado"
>
Ingresar
</router-link>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['userAutenticado'])
}
}
</script>
# Cerrar Sesión
actions: {
cerrarSesion({ commit }) {
commit('setUser', null)
router.push('/ingreso')
},
Navbar.vue
<template>
<button
class="btn btn-dark"
v-if="userAutenticado"
@click="cerrarSesion"
>
Cerrar Sesión
</button>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
methods: {
...mapActions(['cerrarSesion'])
}
}
</script>
# Router Guard (documentación)
https://router.vuejs.org/guide/advanced/meta.html#route-meta-fields (opens new window)
Ejemplo Global before Guards https://router.vuejs.org/guide/advanced/navigation-guards.html (opens new window)
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import store from '../store'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: { requiresAuth: true }
},
{
path: '/editar/:id',
name: 'Editar',
component: () => import(/* webpackChunkName: "about" */ '../views/Editar.vue'),
meta: { requiresAuth: true }
},
{
path: '/registro',
name: 'Registro',
component: () => import(/* webpackChunkName: "about" */ '../views/Registro.vue')
},
{
path: '/ingreso',
name: 'Ingreso',
component: () => import(/* webpackChunkName: "about" */ '../views/Ingreso.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
router.beforeEach((to, from, next) => {
console.log(to.meta.requiresAuth)
if (to.meta.requiresAuth) {
if (store.getters.userAutenticado) {
next()
} else {
next('/ingreso')
}
} else {
next()
}
})
export default router
# LocalStorage
async ingresoUsuario({ commit }, usuario) {
try {
...
commit('setUser', dataDB)
localStorage.setItem('user', JSON.stringify(dataDB))
router.push('/')
} catch (error) {
console.log(error)
}
},
async registrarUsuario({ commit }, user) {
try {
...
commit('setUser', dataDB)
localStorage.setItem('user', JSON.stringify(dataDB))
router.push('/')
} catch (error) {
console.log(error)
}
},
async cargarLocalStorage({ commit, state }) {
if (localStorage.getItem('user')) {
commit('setUser', JSON.parse(localStorage.getItem('user')))
} else {
return commit('setUser', null)
}
...
cerrarSesion({ commit }) {
commit('setUser', null)
localStorage.removeItem('user')
router.push('/ingreso')
},
App.vue
methods: {
...mapActions(['cargarLocalStorage'])
},
created(){
this.cargarLocalStorage()
}
# Deploy
npm run build
npm install -g firebase-tools
firebase login
firebase init
firebase deploy
# Errores
Podemos manejar los errores del formulario:
Vuex
state: {
error: {tipo: null, mensaje: ''}
},
mutations: {
setError(state, payload) {
console.log(payload)
// REINICIAR
if (payload === null) {
return state.error = {tipo: null, mensaje: ''}
}
// LOGIN
if (payload === "EMAIL_NOT_FOUND") {
return state.error = {
tipo: 'email',
mensaje: 'Email no registrado'
}
}
// LOGIN
if (payload === "INVALID_PASSWORD") {
return state.error = {
tipo: 'password',
mensaje: 'Contraseña no válida'
}
}
// LOGIN
if (payload === "EMAIL_EXISTS") {
return state.error = {
tipo: 'email',
mensaje: 'Email ya registrado'
}
}
// REGISTRO
if (payload === "INVALID_EMAIL") {
return state.error = {
tipo: 'email',
mensaje: 'Formato email no válido'
}
}
}
}
async ingresoUsuario({ commit }, usuario) {
try {
...
if (dataDB.error) {
console.log(dataDB.error)
return commit('setError', dataDB.error.message)
}
commit('setUser', dataDB)
commit('setError', null)
localStorage.setItem('user', JSON.stringify(dataDB))
router.push('/')
} catch (error) {
console.log(error)
}
},
async registrarUsuario({ commit }, user) {
try {
...
if (dataDB.error) {
console.log(dataDB.error)
return commit('setError', dataDB.error.message)
}
commit('setUser', dataDB)
commit('setError', null)
localStorage.setItem('user', JSON.stringify(dataDB))
router.push('/')
} catch (error) {
console.log(error)
}
},
Ingreso.vue
<template>
<h1 class="my-5">Ingreso de Usuarios</h1>
<div class="alert alert-warning" v-if="error.tipo !== null">
{{error.mensaje}}
</div>
<form @submit.prevent="procesarFormulario">
<input
type="email"
placeholder="email"
class="form-control my-2"
v-model.trim="email"
:class="[error.tipo === 'email' ? 'is-invalid' : '']"
>
<input
type="password"
placeholder="password"
class="form-control my-2"
v-model.trim="pass1"
:class="[error.tipo === 'password' ? 'is-invalid' : '']"
>
<button
type="submit"
class="btn btn-primary"
:disabled="bloquear"
>
Ingresar
</button>
</form>
</template>
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
email: '',
pass1: '',
}
},
computed: {
bloquear(){
if(!this.email.includes('@')){
return true
}
if(this.pass1.length > 5){
return false
}
return true
},
...mapState(['error'])
},
methods: {
...mapActions(['ingresoUsuario']),
procesarFormulario(){
await this.ingresoUsuario({email: this.email, password: this.pass1})
if(this.error.tipo !== null){
return
}
this.email = '';
this.pass1 = '';
}
}
}
</script>
Registro.vue
<template>
<h1 class="my-5">Registro de Usuarios</h1>
<div class="alert alert-warning" v-if="error.tipo !== null">
{{error.mensaje}}
</div>
<form @submit.prevent="procesarFormulario">
<input
type="email"
placeholder="email"
class="form-control my-2"
v-model.trim="email"
:class="[error.tipo === 'email' ? 'is-invalid' : '']"
>
<input
type="password"
placeholder="password"
class="form-control my-2"
v-model.trim="pass1"
>
<input
type="password"
placeholder="password"
class="form-control my-2"
v-model.trim="pass2"
>
<button
type="submit"
class="btn btn-primary"
:disabled="bloquear"
>
Registrar
</button>
</form>
</template>
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
email: '',
pass1: '',
pass2: ''
}
},
computed: {
bloquear(){
if(!this.email.includes('@')){
return true
}
if(this.pass1.length > 5 && this.pass1 === this.pass2){
return false
}
return true
},
...mapState(['error'])
},
methods: {
...mapActions(['registrarUsuario']),
procesarFormulario(){
await this.registrarUsuario({email: this.email, password: this.pass1})
if(this.error.tipo !== null){
return
}
this.email = '';
this.pass1 = '';
this.pass2 = '';
}
}
}
</script>