In our previous article, we installed and setup Laravel. In this article, we will implement user accounts so users can sign up and sign in to use our app. Let's complete our Passport setup.
First, create a folder in apps
called Models
and move the App\User
model there so it is now App\Models\User
. Change references to App\User
to App\Models\User
in database/factories/UserFactory.php
, config/services.php
, config/auth.php
and app/Http/Controllers/Auth/RegisterController.php
.
Add the Laravel\Passport\HasApiTokens
trait to the App\Models\User
class.
It's better to use UUIDs instead of integer ids in event sourcing to eliminate the risk of having duplicate keys. So, we'll be using UUIDs on our models.
Your App\Models\User
class should look like this:
<?php
namespace App\Models;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable {
use Traits\UsesUuid, HasApiTokens, Notifiable;
protected $guarded = [];
public $incrementing = false;
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Here's the trait app/Models/Traits/UsesUuid.php
and my user migration:
<?php
namespace App\Models\Traits;
use Ramsey\Uuid\Uuid;
trait UsesUuid {
protected static function bootUsesUuid() {
static::creating(function ($model) {
if ((! $model->incrementing) && empty($model->{$model->getKeyName()})) {
$model->{$model->getKeyName()} = (string) Uuid::uuid4();
}
});
}
public function getKeyType() {
return 'string';
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
Modify app/Providers/AuthServiceProvider.php
to look like this:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
}
Set the api driver to passport
in config/auth.php
.
Add \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class
to app/Http/Kernel.php
's $middlewareGroups
.
Run php artisan make:auth
to publish the built-in authentication views. Do not replace layouts/app.blade.php
when asked.
Change the $redirectTo
value to /contacts
in app/Http/Controllers/Auth/RegisterController.php
and app/Http/Controllers/Auth/LoginController.php
.
Alter resources/views/welcome.blade.php
to this:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name', 'Address Book') }}</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Nunito', sans-serif;
font-weight: 200;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 13px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@auth
<a href="{{ url('/contacts') }}">Contacts</a>
@else
<a href="{{ route('login') }}">Login</a>
@if (Route::has('register'))
<a href="{{ route('register') }}">Register</a>
@endif
@endauth
</div>
@endif
<div class="content">
<div class="title m-b-md">
{{ config('app.name', 'Address Book') }}
</div>
</div>
</div>
</body>
</html>
Replace the contents of routes/web.php
with:
<?php
Auth::routes();
Route::get('/', 'HomeController@welcome')->name('welcome');
Route::group(['middleware' => ['auth']], function() {
Route::get('/logout', 'Auth\LoginController@logout');
Route::get('/contacts', 'HomeController@contacts')->name('contacts');
});
Replace the contents of app/Http/Controllers/HomeController.php
with:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller {
public function welcome() {
return view('welcome');
}
public function contacts() {
return view('contacts', ['contacts' => []]);
}
}
Create a new view resources/views/contacts.blade.php
with the following template:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-sm-12">
<!-- -->
</div>
</div>
</div>
@endsection
If you haven't already, run migrations with php artisan migrate:fresh
and start up the app by running php artisan serve
in one command window and npm run watch
in another.
Go ahead and create an account.
Next, we'll be working on contacts.
You can explore the changes here.