Making Dependable #3
Today we’re going to start working towards allowing developers to set a password, and use that (if they prefer) for logging in to Dependable. One of the first steps is to implement password resetting…
Traits And Interfaces
Laravel 5 ships with a User model, to ease the burden of implementing authentication and user session management. Let’s add that to the Developer model:
namespace App\Models;
use Illuminate\Auth;
use Illuminate\Contracts;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Developer extends Model implements
Contracts\Auth\Authenticatable,
Contracts\Auth\CanResetPassword
{
use Auth\Authenticatable;
use Auth\Passwords\CanResetPassword;
// ...
/**
* @return string
*/
public function getEmailForPasswordReset()
{
return $this->github_email;
}
}
This happens in ~/app/Models/Developer.php
In Laravel 4 we had to define methods for returning many column names (like id, email, password and remember_token). The Authenticatable and CanResetPassword interfaces still require these methods, but the similarly named traits provide good defaults.
I removed all of this functionality when I executed php artisan fresh. I didn’t want it those scaffolding classes getting in the way of learning Laravel 5. It would have been less work to keep them, and changed them at this point. I’m not upset about that, because it’s helped me learn some things!
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddDeveloperTableFields extends Migration
{
/**
* Run the migrations.
*/
public function up()
{
Schema::table("developer", function (Blueprint $table) {
$table->rememberToken();
});
}
/**
* Reverse the migrations.
*/
public function down()
{
Schema::table("developer", function (Blueprint $table) {
$table->dropColumn("remember_token");
});
}
}
This happens in ~/database/migrations/
2015_06_02_000000_add_developer_table_fields.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateDeveloperResetTable extends Migration
{
/**
* Run the migrations.
*/
public function up()
{
Schema::create("developer_reset",
function (Blueprint $table) {
$table->string("email")->index();
$table->string("token")->index();
$table->timestamp("created_at");
}
);
}
/**
* Reverse the migrations.
*/
public function down()
{
Schema::drop("developer_reset");
}
}
This happens in ~/database/migrations/
2015_06_02_000000_create_developer_reset_table.php
Aside from setting passwords, I want developers to be able to reset those passwords. For that I needed to add the developer_reset table. None of this code affects the ability to connect and log in with Github/OAuth. It’s juts another way for developers to log in, if they prefer it.
$table->dropColumn(…) can be replaced with
$table->dropRememberToken() in Laravel 5.1.
Next I’ll add the config, views, and handlers for resetting passwords:
"password" => [
"email" => "link",
"table" => "developer_reset",
"expire" => 60,
],
This happens in ~/config/auth.php
@if (session("status"))
{{ session("status") }}
@endif
@if (session("error"))
{{ session("error") }}
@endif
<form method="POST">
<label>
Email:
<input type="email"
name="github_email"
value="{{ old("github_email") }}" />
</label>
<input
type="hidden"
name="_token"
value="{{ csrf_token() }}" />
<input
type="submit"
value="Send Password Reset Link" />
</form>This happens in ~/resources/views/request.blade.php
Click here to reset your password: {{ url("reset/" . $token) }}This happens in ~/resources/views/link.blade.php
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Http\Request;
use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Validator;
Route::get("request", function () {
return view("request");
});
Route::post("request",
function (Request $request, PasswordBroker $passwords) {
$validator = Validator::make($request->all(), [
"github_email" => "required|email",
]);
if ($validator->fails()) {
$error = $validator->errors()
->first("github_email");
return redirect()->back()
->with("error", $error);
}
$response = $passwords->sendResetLink(
$request->only("github_email"),
function (Message $message) {
$message->subject("Password Reset Link");
}
);
if ($response === PasswordBroker::RESET_LINK_SENT) {
return redirect()->back()
->with("status", "Link sent");
}
return redirect()->back()
->with("error", "Invalid email");
}
);
This happens in ~/app/Http/routes.php
I’ve hacked the Laravel magic apart and settled on logic that can remain (at least for the moment) in the routes file. This is similar to what you will find, in the Foundation traits.
I still need to configure the mail settings before this will send the email out! Just a few settings, in .env should be all I need.
Remember: if you’re using Mandrill (as I am) that you need to set your mail details and add your API key to services.php.