Skip to content
Permalink
Browse files

replace token based links with signed links

  • Loading branch information
freekmurze committed Nov 14, 2019
1 parent 5cb8531 commit 5eb45b7537c6ddde51caffae6aceef3edb6faa1d
@@ -20,13 +20,31 @@ You can install the package via composer:
composer require spatie/laravel-welcome-notification
```

The package ships with two views you should style yourself. You can publish the views with this command:
### Migrating the database

You must publish provided by this package by executing this command:

```bash
php artisan vendor:publish --provider="Spatie\WelcomeNotification\WelcomeNotificationServiceProvider" --tag="migrates"
```

Next, you must migrate your database.

```php
php artisan migrate
```

### Preparing the view

The package ships with a welcome view you should style yourself. You can publish the views with this command:

```bash
php artisan vendor:publish --provider="Spatie\WelcomeNotification\WelcomeNotificationServiceProvider" --tag="views"
```

The `welcome` view will be rendered when somebody click the welcome link in the welcome notification mail. The `invalidWelcomeLink` will be rendered whenever somebody clicks an invalid welcome link.
The `welcome` view will be rendered when somebody click the welcome link in the welcome notification mail.

### Preparing the WelcomeController

Next you'll need to create a controller of your own that will extend `Spatie\WelcomeNotification\WelcomeController`

@@ -40,21 +58,32 @@ class MyWelcomeController extends BaseWelcomeController
}
```

Finally, you'll have to register these routes
### Registering the routes

You'll have to register these routes:

```php
use App\Http\Controllers\Auth\MyWelcomeController::class;
use Spatie\WelcomeNotification\WelcomesNewUsers;
use App\Http\Controllers\Auth\WelcomeController;
Route::get('welcome/{user}/{token}', [MyWelcomeController::class], 'showWelcomeForm'])->name('welcome');
Route::post('welcome', [MyWelcomeController::class, 'savePassword'])->name('welcome.save-password');
Route::group(['middleware' => ['web', WelcomesNewUsers::class,]], function () {
Route::get('welcome/{user}', [WelcomeController::class, 'showWelcomeForm'])->name('welcome');
Route::post('welcome/{user}', [WelcomeController::class, 'savePassword']);
});
```

### Preparing the user model

You must apply the `\Spatie\WelcomeNotificationReceivesWelcomeNotification` trait to your `User` model.

## Usage

Here's how you can send a welcome notification to a user that you just created.

```php
$user->notify(new Spatie\WelcomeNotification\WelcomeNotification());
$expiresAt = now()->addDay();
$user->sendWelcomeNotification($expiresAt);
```

## Handling successful requests
@@ -87,6 +116,15 @@ class MyCustomWelcomeNotification extends WelcomeNotification
}
```

To use the custom notification you must add a method called `sendWelcomeNotification` to your `User` model.

```php
public function sendWelcomeNotification(Carbon $validUntil)
{
$this->notify(new MyCustomWelcomeNotification($validUntil));
}
```

### Testing

```bash
@@ -19,7 +19,8 @@
"php": "^7.3",
"illuminate/auth": "^6.5",
"illuminate/notifications": "^6.5",
"illuminate/queue": "^6.5"
"illuminate/queue": "^6.5",
"spatie/test-time": "^1.1"
},
"require-dev": {
"orchestra/testbench": "^4.3",
@@ -0,0 +1,15 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddWelcomeValidUntilFieldToUsersTable extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->timestamp('welcome_valid_until')->nullable();
});
}
}

This file was deleted.

@@ -1,8 +1,7 @@
<form method="POST" action="{{ route('welcome.save-password') }}">
<form method="POST" action="{{ route('welcome', $user) }}">
@csrf

<input type="hidden" name="email" value="{{ $user->email }}"/>
<input type="hidden" name="token" value="{{ $token }}"/>

<div>
<label for="password">{{ __('Password') }}</label>
@@ -2,10 +2,20 @@
namespace Spatie\WelcomeNotification;
use Carbon\Carbon;
trait ReceivesWelcomeNotification
{
public function sendWelcomeNotifcation()
public function sendWelcomeNotification(Carbon $validUntil)
{
$this->notify(new WelcomeNotification());
$this->notify(new WelcomeNotification($validUntil));
}
public function markAsInitialPasswordSet()
{
$this->welcome_valid_until = null;
$this->save();
return $this;
}
}
@@ -2,45 +2,46 @@
namespace Spatie\WelcomeNotification;
use Illuminate\Foundation\Auth\RedirectsUsers;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Spatie\WelcomeNotification\Tests\Models\User;
use Symfony\Component\HttpFoundation\Response;
class WelcomeController
{
use ResetsPasswords;
use RedirectsUsers;
public function showWelcomeForm(Request $request, User $user, string $token = null)
public function showWelcomeForm(Request $request, User $user)
{
if (! $this->broker()->tokenExists($user, $token)) {
return $this->invalidLinkResponse();
}
return view('welcomeNotification::welcome')->with([
'token' => $token,
'email' => $request->email,
'user' => $user,
]);
}
public function savePassword(Request $request)
public function savePassword(Request $request, User $user)
{
return $this->reset($request);
}
$request->validate($this->rules());
protected function invalidLinkResponse()
{
return response()->view('welcomeNotification::invalidWelcomeLink', [], 404);
$user->password = bcrypt($request->password);
$user->welcome_valid_until = null;
$user->save();
auth()->login($user);
return $this->sendPasswordSavedResponse();
}
protected function sendPasswordSavedResponse(): Response
{
return redirect()->to($this->redirectPath())->with('status', 'Welcome! You are now logged in!');
}
protected function sendResetResponse(): Response
protected function rules()
{
return $this->sendPasswordSavedResponse();
return [
'password' => 'required|confirmed|min:6',
];
}
}
@@ -2,26 +2,33 @@
namespace Spatie\WelcomeNotification;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\User;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\URL;
class WelcomeNotification extends Notification
{
/** @var \Illuminate\Foundation\Auth\User */
public $user;
/** @var string */
public $token;
/** @var string */
public $showWelcomeFormUrl;
/** @var \Closure|null */
public static $toMailCallback;
/** @var \Carbon\Carbon */
public $validUntil;
public function __construct(Carbon $validUntil)
{
$this->validUntil = $validUntil;
}
public function via($notifiable)
{
return ['mail'];
@@ -56,8 +63,11 @@ protected function initializeNotificationProperties(User $user)
{
$this->user = $user;
$this->token = Password::getRepository()->create($user);
$this->user->welcome_valid_until = $this->validUntil;
$this->user->save();
$this->showWelcomeFormUrl = route('welcome', [$this->user->id, $this->token]);
$this->showWelcomeFormUrl = URL::temporarySignedRoute(
'welcome', $this->validUntil, ['user' => $user->id]
);
}
}
@@ -14,5 +14,11 @@ public function boot()
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/welcomeNotification'),
], 'views');
if (! class_exists('AddWelcomeValidUntilFieldToUsersTable')) {
$this->publishes([
__DIR__ . '/../database/migrations/add_welcome_valid_until_field_to_users_table.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_add_welcome_valid_until_field_to_users_table.php'),
], 'migrations');
}
}
}
@@ -0,0 +1,31 @@
<?php
namespace Spatie\WelcomeNotification;
use Carbon\Carbon;
use Closure;
class WelcomesNewUsers
{
public function handle($request, Closure $next)
{
if (! $request->hasValidSignature()) {
abort(401, 'The welcome link does not have a valid signature or is expired.');
}
if (! $request->user) {
abort(401, 'Could not find a user to be welcomed.');
}
if (is_null($request->user->welcome_valid_until)) {
return abort(401, 'The welcome link has already been used.');
}
//dd(Carbon::createFromTimestamp($request->user->welcome_valid_until), $request->user->welcome_valid_until);
if (Carbon::create($request->user->welcome_valid_until)->isPast()) {
return abort(401, 'The welcome link has expired.');
}
return $next($request);
}
}
@@ -2,11 +2,16 @@
namespace Spatie\WelcomeNotification\Tests;
use AddWelcomeValidUntilFieldToUsersTable;
use CreateAuthTables;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Foundation\Auth\User;
use Illuminate\Routing\Middleware\ValidateSignature;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Schema;
use Orchestra\Testbench\TestCase as Orchestra;
use Spatie\WelcomeNotification\WelcomesNewUsers;
use Spatie\WelcomeNotification\WelcomeController;
use Spatie\WelcomeNotification\WelcomeNotificationServiceProvider;
@@ -18,7 +23,9 @@ public function setUp(): void
Model::unguard();
$this->setUpRoutes();
$this
->setUpRoutes()
->migrateDatabase();
$this->withoutExceptionHandling();
}
@@ -39,19 +46,34 @@ protected function getEnvironmentSetUp($app)
'prefix' => '',
]);
include_once __DIR__.'/database/migrations/create_auth_tables.php.stub';
(new CreateAuthTables())->up();
config()->set('auth.providers.users.model', User::class);
config()->set('app.key', 'base64:CmNWRD9Yia6R0YVuFal7MUuE32Iqzk2whpEeknTSexc=');
config()->set('mail.driver', 'log');
}
protected function setUpRoutes(): void
protected function setUpRoutes()
{
Route::group(['middleware' => ['web', WelcomesNewUsers::class,]], function () {
Route::get('welcome/{user}', ['\\'.WelcomeController::class, 'showWelcomeForm'])->name('welcome');
Route::post('welcome/{user}', ['\\'.WelcomeController::class, 'savePassword']);
});
return $this;
}
protected function migrateDatabase()
{
Route::group(['middleware' => ['web']], function () {
Route::get('welcome/{user}/{token}', ['\\'.WelcomeController::class, 'showWelcomeForm'])->name('welcome');
Route::post('welcome', ['\\'.WelcomeController::class, 'savePassword'])->name('welcome.save-password');
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('email');
$table->string('name');
$table->string('password')->nullable();
$table->timestamps();
});
include_once __DIR__ . '/../database/migrations/add_welcome_valid_until_field_to_users_table.php.stub';
(new AddWelcomeValidUntilFieldToUsersTable())->up();
return $this;
}
}

0 comments on commit 5eb45b7

Please sign in to comment.
You can’t perform that action at this time.