Hello Coders !! This article is about the Laravel + VueJS – Build a login and register web app. In this article we are using Laravel framework and latest VueJS frontend framework to build a basic and first step of any web app. We are build a Login and Register feature using this article.
Let us start with installation of a latest version of Laravel.
Step 1: Install and setup Laravel
Just follow these steps to install and setup laravel.
If you know laravel setup then first complete the installation of it and if you are not aware of it then follow the article Install Laravel to install laravel and setup laravel.
After successfully installed laravel you just need to change in this file. ../app/Providers/AppServiceProvider.php After changing the code in file it will look like this.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
}
Here we added schema in boot function.
Install tymon/jwt-auth package
To install this package you need open the composer.json file placed in root directory of a project and add this line in require.
"laravel/ui": "^2.0",
"tymon/jwt-auth": "dev-develop",
Therefore, update the composer form the terminal within the project directory.
composer update
This command will install the package and the dependencies. Now we are going to publish the package using the below command.
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
Step 2: User interface setup in Laravel
User model file
Now open the user.php model file from inside the app folder and add below code in it.
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Compare and check your old code in file and you will notice what change has done in this file.
User Controller file
Open/Create the ../app/Http/Controllers/UserController.php file and add the below code in it.
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Facades\JWTFactory;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Tymon\JWTAuth\JWTManager as JWT;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
class UserController extends Controller
{
public function register(Request $request){
$validator = Validator::make($request->json()->all(), [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
]);
if($validator->fails()){
return response()->json($validator->errors()->toJson(), 400);
}
$user = User::create([
'name' => $request->json()->get('name'),
'email' => $request->json()->get('email'),
'password' => Hash::make($request->json()->get('password')),
]);
$token = JWTAuth::fromUser($user);
return response()->json(compact('user','token'), 201);
}
public function login(Request $request){
$credentials = $request->json()->all();
try {
if(! $token = JWTAuth::attempt($credentials)){
return response()->json(['error'=>'invalid Credentials'], 400);
}
}catch (JWTException $e){
return response()->json(['error'=>'could_not_create_token'], 500);
}
return response()->json(compact('token'));
}
public function getAuthenticatedUser(){
try{
if(!$user = JWTAuth::parseToken()->authenticate()){
return response()->json(['user_not_found'], 400);
}
}catch (TokenExpiredException $e){
return response()->json(['token_expired'], $e->getStatusCode());
}catch (TokenInvalidException $e){
return response()->json(['token_invalid'], $e->getStatusCode());
}catch (JWTException $e){
return response()->json(['token_absent'], $e->getStatusCode());
}
return response()->json(compact('user'));
}
}
In this controller, we have added the functions regarding the register, login, and get authenticated user.
Open ../config/app.php and add below service providers and aliases.
in providers add this in existing code.
'providers' => [
..
\Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]
In aliases add this in existing code.
'aliases' => [
..
'JWTAuth' => \Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => \Tymon\JWTAuth\Facades\JWTFactory::class,
],
Step 3: Create Routes
To create the routes open routes file located here ../routes/web.php and add below routes in it.
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
Now open API routes file located here ../routes/api.php and add below routes in it.
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('register','UserController@register');
Route::post('login','UserController@login');
Route::get('profile','UserController@getAuthenticatedUser');
Route::middleware('auth:api')->get('/user', function(Request $request){
return $request->user();
});
After you are done with creating web routes. Open the project in the browser and check that is it working properly or not if not the solve the error first.
Same as we need to check the created API’s using postman a chrome extension. Just check the register and login API’s there as we have already written the code in UserController.php file for this API’s.
Install Dependencies
If you do not have the laravel UI installed for bootstrap the run below command.
composer require laravel/ui
php artisan ui vue
Make sure you have installed node, npm and vue. If you haven’t installed it then follow the below command.
npm install && npm run dev
php artisan ui vue --auth
npm install
Init Webpack client
To init webpack client run below command.
vue init webpack client
When you running this command you will be asked some questions so just give the answer most of are will be in “Yes” and complete the process and in the last question use NPM.
After successfully run this command you will find the client folder created in your project root directory.
Now open package.json file form this client directory.
../client/package.json and add the dependencies if it’s not there. Add axios and bootstrap dependencies. After adding it will look like this.
"dependencies": {
"axios": "^0.18.0",
"bootsrap": "^4.4",
"vue": "^2.5.2",
"vue-router": "^3.0.1"
},
Now from the terminal reach up to the client directory.
cd client
After that, Run this command in terminal.
npm i
This command will install the packages that we have just added above.
Now, Open ../client/config/index.js file and update below code in it.
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api' : {
target : 'http://loginvue.test/',
changeOrigin: true
}
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
/**
* Source Maps
*/
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}
Open ../client/src/main.js file and update code same as below.
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
require('.../node_modules/bootstrap/dist/css/bootstrap.css')
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
Open ../client/src/App.vue file and update code same as below.
<template>
<div id="app">
<navbar></navbar>
<router-view/>
</div>
</template>
<script>
import Navbar from './components/Navbar'
export default {
name: 'App',
components: {
'Navbar': Navbar
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
open file ../client/src/router/index.js and add below code in it.
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
import Home from '@/component/home'
import Login from '@/component/Login'
import Register from '@/component/Register'
import Profile from '@/component/Profile'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/register',
name: 'Register',
component: Register
},
{
path: '/profile',
name: 'Profile',
component: Profile
}
]
})
Here we have added the routes for vue. Now we are going to create the component of vue inside this folder ../client/src/components and create a new file for that and will add the code in it.
EventBus.vue
../client/src/components/EventBus.vue
This file contains below code in it.
<script>
import vue from 'vue'
const EventBus = new Vue()
export default EventBus
</script>
Home.vue
./client/src/components/Home.vue
This file contains below code in it.
<template>
<div class="container">
<div class="jumbotron mt-5">
<div class="col-sm-8 mx-auto">
<h1 class="text-center"> Welcome</h1>
</div>
</div>
</div>
</template>
Login.vue
../client/src/components/Login.vue
This file contains below code in it.
<template>
<div class="container">
<div class="row">
<div class="col-md-6 mt-5 mx-auto">
<form v-on:submit.prevent="Login">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<div class="form-group">
<label for="email"> Email Address</label>
<input type="email" v-model="email" class="form-control" name="email" placeholder="Email Address">
</div>
<div class="form-group">
<label for="password"> Password</label>
<input type="password" v-model="password" class="form-control" name="password" placeholder="Password">
</div>
<button class="btn btn-lg btn-primary btn-block">Sign in</button>
</form>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import router from '../router'
import EventBus from '../EventBus'
export default{
data(){
return {
email: '',
password: '',
}
},
methods:{
login() {
axios.post('/api/login',
{
email:this.email,
password:this.password,
})
.then((res) => {
localStorage.setItem('usertoken', res.data.token)
this.email = ''
this.password = ''
router.push({name: 'Profile'})
})
.catch((err) => {
console.log(err)
})
this.emitMethod()
},
emitMethod() {
EventBus.$emit('logged-in','loggedin')
}
}
}
</script>
Navbar.vue
../client/src/components/Navbar.vue
This file contains below code in it.
<template>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark rounded">
<button class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbar1"
aria-controls="navbar1"
aria-expanded="false"
aria-label="Toggle Navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-md-center" id="navbar1">
<ul class="navbar-nav">
<li class="nav-item">
<router-link class="nav-link" to="/">home</router-link>
</li>
<li v-if="auth==''" class="nav-item">
<router-link class="nav-link" to="/login">Login</router-link>
</li>
<li v-if="auth==''" class="nav-item">
<router-link class="nav-link" to="/register">Register</router-link>
</li>
<li v-if="auth=='loggedin'" class="nav-item">
<router-link class="nav-link" to="/profile">Profile</router-link>
</li>
<li v-if="auth=='loggedin'" class="nav-item">
<router-link class="nav-link" href="">Logout</router-link>
</li>
</ul>
</div>
</nav>
</template>
<script>
import EventBus from '../EventBus'
export default {
data() {
return {
auth: '',
user: '',
}
},
methods:{
logout() {
localStorage.removeItem('usertoken')
}
},
mounted() {
EventBus.$on('logged-in', status => {
this.auth - status
})
}
}
</script>
Register.vue
../client/src/components/Register.vue
This file contains below code in it.
<template>
<div class="container">
<div class="row">
<div class="col-md-6 mt-5 mx-auto">
<form v-on:submit.prevent="register">
<h1 class="h3 mb-3 font-weight-normal">Register</h1>
<div class="form-group">
<label for="first_name"> First Name</label>
<input type="text" v-model="first_name" class="form-control" name="first_name" placeholder="first name">
</div>
<div class="form-group">
<label for="last_name"> Last Name</label>
<input type="text" v-model="last_name" class="form-control" name="last_name" placeholder="last name">
</div>
<div class="form-group">
<label for="email"> Email Address</label>
<input type="email" v-model="email" class="form-control" name="email" placeholder="Email Address">
</div>
<div class="form-group">
<label for="password"> Password</label>
<input type="password" v-model="password" class="form-control" name="password" placeholder="Password">
</div>
<button class="btn btn-lg btn-primary btn-block">Register</button>
</form>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import router from '../router'
export default{
data(){
return {
first_name: '',
last_name: '',
email: '',
password: '',
}
},
methods:{
register() {
axios.post('/api/register',
{
name:this.first_name +' '+ this.last_name,
email:this.email,
password:this.password,
})
.then((res) => {
console.log(res)
router.push({name: 'Login'})
})
.catch((err) => {
console.log(err)
})
},
}
}
</script>
Profile.vue
../client/src/components/Profile.vue
This file contains below code in it.
<template>
<div class="container">
<div class="jumbotron mt-5">
<div class="col-sm-8 mx-auto">
<h1 class="text-center">Profile</h1>
</div>
<table class="table col-md-6 mx-auto">
<tbody>
<tr>
<td>Name</td>
<td>{{whole_name}}</td>
</tr>
<tr>
<td>Email</td>
<td>{{email}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default{
data() {
this.getUser().then(res => {
this.wholename = res.user.name
this.email = res.user.email
return res
})
return {
wholename: '',
email: ''
}
},
methods: {
getUser() {
return axios.get('api/profile', {
headers:{
Authorization: 'Bearer' ${localStorage.usertoken}
}
})
.then(res => {
return res.date
})
.catch(err =>{
console.log(err)
})
}
}
}
</script>
After creating this file just run the project it will be look like this.
Here we are done with the Laravel + VueJS – Build a login and register web app tutorial. Enjoy Coding with our companionship.
Excellent blog here! Also your site loads up fast! What host are you using?
Can I get your affiliate link to your host? I wish my website loaded up as
quickly as yours lol