2015年11月23日 星期一

Email activation with Laravel5

TODAY’S GOAL: To set up user registration via email activation
It’s week one of my journey and I’m feeling positive! I have a plan and I’m ready to go. After having installed Laravel I’ve decided that the first thing I’m going to work on is the user authentication side of things.

Registering a user via email confirmation

Out of the box Laravel 5 actually does all the user authentication for you, I really have very little to do. But one piece of functionality I do want to add in is making sure the user confirms registration by clicking on a link I send to their email. The primary reason for this is to prevent spam accounts being created. Let me show you how I did it.
The way this will work is as follows:
  1. A user registers an account.
  2. They are sent an email.
  3. User clicks on link in email and account is activated.
  4. User gets logged in.

Update the Users table

The first thing to do is update my users table to include a column to hold an activation code and also a column to set an account to active. I run the following command:
php artisan make:migration update_users_table
Laravel will then create the required migration file, I then update the up method to look like this:
public function up()
{
Schema::table('users', function(Blueprint $table)
{
$table->string('activation_code')->after('password');
$table->integer('active')->default(0)->after('activation_code');
});
}
This will update my users table with what I need. The after method which I chain to the end simply tells the migration to add the column after a specific field.
I ran the following command in the console…
php artisan migrate
and from a database perspective I’m all done, now I can store an activation code and active status on the users table.

Modifying the authentication trait

The next step is to modify the registration process. Typically when a user gets registered they are logged in and redirected to the home page, I want to add in the extra step requiring email confirmation. I found this to be a straight forward process.
The following file handles the registration process:
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesAndRegistersUsers.php
Editing vendor files is not generally considered good practice but for the sake of speed I decided to brake that rule for now (I will refactor this I promise and update this post accordingly!!).
My postRegister method now looks like this:

public function postRegister(Request $request)
{
$validator = $this->registrar->validator($request->all());
if ($validator->fails())
{
$this->throwValidationException(
$request, $validator
);
}
$activation_code = str_random(60) . $request->input(’email’);
$user = new User;
$user->name = $request->input(‘name’);
$user->email = $request->input(’email’);
$user->password = bcrypt($request->input(‘password’));
$user->activation_code = $activation_code;
if ($user->save()) {
$data = array(
‘name’ => $user->name,
‘code’ => $activation_code,
);
\Mail::queue(’emails.activateAccount’, $data, function($message) use ($user) {
$message->to($user->email, ‘Please activate your account.’);
});
return view(‘user.activateAccount’);
}
else {
\Session::flash(‘message’, ‘Your account couldn\’t be create please try again’);
return redirect()->back()->withInput();
}
}
Normally after registration the user is logged in and redirected, but I’ve made a few modifications.
Allow me to explain what I did here:
  1. After a user submits a registration form they are sent to this method
  2. If validation is successful I generate a random string (activation code) and a user object
  3. I store these values in the users table
  4. After saving the data I use the Mail facade and email the user, passing through the activation code
You’ll notice I have a backslash in front of each Facade when I use it… Don’t forget that Laravel 5 makes use of proper namespacing, this was a really frustrating thing to debug. The backslash refers to the root namespace of the application where the Facades live.
Now the user has a new email in their inbox :)

Add in a new route and modify Auth controller

At this point it was time to add in a new route to handle the link that gets clicked in the email which looked like so:
Route::get('activate/{code}', 'Auth\AuthController@activateAccount');
When the user clicks on the link they go to the below function which looks like:
public function activateAccount($code, User $user)
{
   if($user->accountIsActive($code)) {
\Session::flash('message', 'Success, your account has been activated.');
return redirect('home');
}
\Session::flash('message', 'Your account couldn\'t be activated, please try again');
return redirect('home');
}
This function checks to see if the user is active and redirects accordingly. I’ve further abstracted that logic and store the accountIsActive method in my User model:

public function accountIsActive($code) {
$user = User::where('activation_code', '=', $code)->first();
$user->active = 1;
$user->activation_code = '';
if($user->save()) {
\Auth::login($user);
}
return true;
}
So basically the user clicks on the link in the email, the above method gets their record from the database, sets their active status to 1 and then logs them in. I also added the following snippet to my Authenticate.php middleware file so that only active users could view authenticated data.
if (!\Auth::user()->active) {
\Session::flash('message', 'Please activate your account to proceed.');
return redirect()->guest('home');
}

Email registration activation summary

I’m happy with my start on this app, I’ve spent about 3 hours so far to get it where it is, I know I need to do some refactoring soon but at least it’s a decent start. This first week has been spent doing a lot of research on what’s new with Laravel 5 and as such I’ve probably spent less time coding and more time studying. Over the next few weeks I hope to speed things up a bit.
This past week I’ve spent a lot more time than I wanted simply debugging small bugs as I’m still getting familiar with Laravel 5, it’s been annoying and the documentation on the web is still playing catch ups but hey that’s all part of the challenge right?
That’s it for now I hope you enjoyed, stay tuned as my next step is to integrate social media logins using Socialite.

refer : http://www.codeanchor.net/blog/email-activation-laravel/
github : https://github.com/iateadonut/laravel5-email-authentication

Appendix :
'encryption' => 'tls' or 'encryption' => 'ssl'
"port 465 (with SSL) and port 587 (with TLS)"

沒有留言:

wibiya widget