24/01/2019, 15:21

Đăng nhập bằng MagicLink thay vì Password!

Bước xác minh, trong nhiều năm qua, đã có những bước tiến mạnh mẽ. Chúng ta đã chứng kiến sự thay đổi từ tổ hợp email-password sang xác minh mạng xã hội, và cuối cùng là xác minh lược bỏ password (mà thực ra lại giống kiểu xác minh "chỉ email" hơn). Trong trường hợp login lược bỏ password, ứng ...

Bước xác minh, trong nhiều năm qua, đã có những bước tiến mạnh mẽ. Chúng ta đã chứng kiến sự thay đổi từ tổ hợp email-password sang xác minh mạng xã hội, và cuối cùng là xác minh lược bỏ password (mà thực ra lại giống kiểu xác minh "chỉ email" hơn). Trong trường hợp login lược bỏ password, ứng dụng sẽ giả định bạn nhận login link từ inbox nếu email được cung cấp đúng là của bạn.

Quy trình thường thấy của một hệ thống login không password diễn ra như sau:

  • Người dùng truy cập vào login page
  • Nhập địa chỉ email và xác nhận
  • Một đường link được gửi đến email
  • Khi click vào link, họ được chuyển hướng trở lại ứng dụng và đăng nhập
  • Đường link bị vô hiệu hóa

Đây là một cách xác minh tiện lợi nếu bạn không tài nào nhớ được password cho ứng dụng đó, nhưng bạn lại nhớ email khai báo lúc đăng ký. Một điểm thú vị là thậm chí cả Slack cũng dùng đến kỹ thuật này.

Trong bài viết này, chúng ta sẽ tìm cách tích hợp hệ thống MagicLink vào ứng dụng Laravel.

1. Tạo ứng dụng

1.1 Tạo project Laravel thông qua composer

composer create-project --prefer-dist laravel/laravel magiclink

1.2 Chuẩn bị dữ liệu

Sửa lại 1 chút file migrate cho bảng users:

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name')->nullable();
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password')->nullable();
    $table->string('magic_link_token')->nullable();
    $table->rememberToken();
    $table->timestamps();
});

1.3 Generate chức năng login mặc định của Laravel

Bằng cách chạy lệnh:

php artisan make:auth

chúng ta được như sau:

1.4 Thêm view "Login bằng MagicLink"

Thêm đường link "Login with MagicLink" để chuyển hướng người dùng sang custom login view, tại đây người dùng sẽ cung cấp địa chỉ email mà không cần nhập password.

// resources/views/layouts/app.blade.php
...
@guest
    <li class="nav-item">
        <a class="nav-link" href="{{ route('magic_link.show') }}">{{ __('Login with MagicLink') }}</a>
    </li>
    <li class="nav-item">
        <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
    </li>
    @if (Route::has('register'))
        <li class="nav-item">
            <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
        </li>
    @endif
@else
...
// resources/views/auth/magic_link/login.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Login') }}</div>

                <div class="card-body">
                    @if (session('success'))
                        <div class="alert alert-success">
                            {{ session('success') }}
                        </div>
                    @endif
                    <form method="POST" action="{{ route('magic_link.send_token') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : ' }}" name="email" value="{{ old('email') }}" required autofocus>

                                @if ($errors->has('email'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : ' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Send Magic Link') }}
                                </button>

                                <a class="btn btn-link" href="{{ route('login') }}">
                                    {{ __('Login with Password') }}
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Chúng ta được:

1.5 Tạo Controller và thêm Routes:

// routes/web.php
...
Route::get('/login/magic-link', 'Auth[email protected]')->name('magic_link.show');
Route::post('/login/magic-link', 'Auth[email protected]')->name('magic_link.send_token');
Route::get('/login/magic-link/{token}', 'Auth[email protected]')->name('magic_link.authenticate');
...
// app/Http/Controllers/Auth/MagicLoginController.php
<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;

class MagicLinkLoginController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function showLoginForm()
    {
        return view('auth.magic_link.login');
    }
}

1.6 Xử lý gửi MagicLink

Thêm phần code xử lí tạo token và gửi MagicLink cho email:

// app/Http/Controllers/Auth/MagicLoginController.php
...
use IlluminateHttpRequest;
use AppUser;
use Mail;
...
public function sendToken(Request $request)
{
    $this->validate($request, [
        'email' => 'required|email|max:255|exists:users,email'
    ]);

    $user = User::whereEmail($request->email)->first();

    $user->update([
        'magic_link_token' => str_random(50),
    ]);

    $magicLink = route('magic_link.authenticate', [
        $user->magic_link_token,
        'remember' => $request->get('remember'),
        'email' => $request->email,
    ]);

    Mail::raw(
        "Click link to login: $magicLink",
        function ($message) use ($user) {
            $message->to($user->email)
                    ->subject('Click the magic link to login');
        }
    );

    return back()->with('success', 'We've sent you a magic link!');
}
...

Thử nhập email và bấm nút "Send Magic Link" được:

Mail nhận được:

1.7 Xử lí authenticate(chứng thực) bằng MagicLink

Giờ thì chúng ta đã có URL, tạo controller action để xử lý chuỗi sự kiện xảy ra khi người dùng click vào URL từ email. Tạo action authenticate trong MagicLoginController. Chúng ta sẽ xác minh người dùng ngay trong method này:

// app/Http/Controllers/Auth/MagicLoginController.php
...
use Auth;
...
public function authenticate(Request $request, $token)
{
    $user = User::whereMagicLinkToken($token)->first();
    Auth::login($user, $request->remember);

    return redirect('home');
}
...

Sau khi click vào link trong email chúng ta được kết quả:

2. Tổng kết

Như vậy, chúng ta đã thành công với cách đăng nhập không password bên cạnh cách xác minh truyền thống. Nhiều người cho rằng cách này sẽ mất nhiều thời gian hơn cách đăng nhập bằng password thông thường, nhưng dùng password liệu có nhanh và bảo mật hơn chăng?

Hi vọng bài viết hữu ích với các bạn             </div>
            
         </div>
      </div>
      
      
      <div class=

Bài liên quan

Đăng nhập bằng MagicLink thay vì Password!

Bước xác minh, trong nhiều năm qua, đã có những bước tiến mạnh mẽ. Chúng ta đã chứng kiến sự thay đổi từ tổ hợp email-password sang xác minh mạng xã hội, và cuối cùng là xác minh lược bỏ password (mà thực ra lại giống kiểu xác minh "chỉ email" hơn). Trong trường hợp login lược bỏ password, ...

Tạ Quốc Bảo viết 15:21 ngày 24/01/2019

Thiết kế form đăng nhập bằng CSS3

Để tìm hiểu kỹ hơn về CSS3 chúng ta sẽ làm một ứng dụng đơn giản nhỏ, đó là từng bước thiết kế trang đăng nhập cho website hay blog của bạn. Các bạn có thể xem demo tại đây. Trước tiên chúng ta sẽ tạo cấu trúc HTML cho form đăng nhập này : <div> <h1>FORM ĐĂNG ...

Trịnh Tiến Mạnh viết 19:57 ngày 04/10/2018

Bài 11: Viết ứng dụng đăng nhập bằng PHP và MYSQL

Bài 11: Viết ứng dụng đăng nhập bằng PHP và MYSQL Ở những bài trước chúng ta đã học qua các kiến thức trọng yếu về PHP . Tuy nhiên, để có thể xây dựng một website hoàn chỉnh bằng những kiến thức đó thì quả thật không đơn giản. Bởi vì các kiến thức qua sách vở và tài liệu dù ...

Hoàng Hải Đăng viết 15:11 ngày 19/09/2018

Dùng textsms.net để sử dụng SMS Verify tài khoản đăng nhập bằng số điện thoại

Khi sử dụng các app như viber hay zalo... chúng ta sử dụng số điện thoại của mình để tạo tài khoản, sau khi nhập số điện thoại vào sẽ có một SMS gửi về mã pin để chúng ta nhập vào verify mã pin. Nếu đúng thì tạo tài khoản thành công. Bài viết này mình dựa vào 1 bên thứ 3 là textsms.net Đầu ...

Tạ Quốc Bảo viết 08:42 ngày 07/09/2018

Project RoR với đăng nhập bằng Facebook đơn giản

1. Mở đầu: Đối với một người dùng, khi phải thường xuyên nhớ tài khoản và mật khẩu của từng ứng dụng luôn là vấn đề đau đầu, ngày xưa thì thường hay viết vào trong một cuốn sổ hay viết trong một tờ lịch nhưng đó không phải là một cách tốt vì nếu mất sổ hay chữ phai màu theo thời gian thì sẽ gây ...

Hoàng Hải Đăng viết 18:12 ngày 12/08/2018
0