はじめに
現在SIer5年目でjavascript(Jqueryのみ)、PHP(フレームワーク無し)を2年ほど、C#(Windowsアプリ)3年ほどやってきました。
色々なご縁があり、個人で最近Webサービスの立ち上げをやることになったのですが何せ本当にWebサービスを立ち上げるための知識がほぼ0に等しいです
ただ今後のキャリアを考えた時に今のままではいけないと思いチャレンジすることにしました。
まずは最初に技術を習得しないといけないので、学ぶ&アウトプットするために毎回投稿していこうと思います。
今後身についていこうと思ってるのは下記のような技術です。
AWS
Docker
CI/CD環境の構築
Laravel
Nuxt.js
今回はLaravel+Nuxtについて学んでいきます。
今回学ぶこと
Laravel+Nuxtでのログイン機能を作成していこうかと思います。
jwt-authを使用してログインを実現してきます。
参考サイト
前提
Laravel 5.8
Nuxt 2.5.4
jwt-auth
このチュートリアルで勉強してみました
Laravel + NuxtJS authentication
Laravel + NuxtJS認証:プロジェクトの設定
まずはLaravel、Nuxtのプロジェクト設定を行う
認証機能を追加する
php artisan make:auth
/app/Models
にUser.phpを移動する
mkdir ./app/Models
mv ./app/User.php ./app/Models
参照しているファイルのパスを修正する'
- namespace App\;
+ namespace App\Models;
- use App\User;
+ use App\Models\User;
- 'model' => App\User::class,
+ 'model' => App\Models\User::class,
- 'model' => App\User::class,
+ 'model' => App\Models\User::class,
マイグレーションの実行
php artisan migrate
composerでjws-authをインストールする
まずはインストールをする
composer require tymon/jwt-auth dev-develop
次のコマンドを実行してパッケージ設定ファイルを公開します。
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
秘密鍵を作成する
php artisan jwt:secret
注意
Laravelのバージョンによって必要な手順が異なるため
公式サイトを確認する
jwt-authのトークン発行を有効にする
JWT用の関数を追加する
- class User extends Authenticatable
+ class User extends Authenticatable implements JWTSubject
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
認証ガードを設定する
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
...
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
LaravelのAPIを定義する
LaravelでAPIのルーティングを設定していく
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group(['prefix' => '/auth', ['middleware' => 'throttle:20,5']], function (){
Route::post('/register', 'Auth\RegisterController@register');
Route::post('/login', 'Auth\LoginController@login');
});
Route::group(['middleware' => 'auth:api'], function (){
Route::get('/me', 'MeController@index');
Route::get('/auth/logout', 'MeController@logout');
});
各APIを実装していく
ユーザ登録APIのコントローラを実装する
※本来はPasswordは2回入力してもらうためにValidationはconfirmation
も入れるべきですが今回が簡単に実装するために省略します。
<?php
namespace App\Http\Controllers\Auth;
use App\Models\User;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Tymon\JWTAuth\JWTAuth;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = '';
protected $auth;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct(JWTAuth $auth)
{
$this->auth = $auth;
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* 登録関数をオーバライドする
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if(!$validator->fails()){
$user = $this->create($request->all());
$token = $this->auth->attempt($request->only(`email`, 'password'));
return response()->json([
'success' => true,
'data' => $user,
'token' => $token
], 200);
}
return response()->json([
'success' => false,
'errors' => $validator->errors()
], 422);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}
ログインAPIのコントローラを実装する
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\JWTAuth;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '';
protected $auth;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct(JWTAuth $auth)
{
$this->auth = $auth;
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return response()->json([
'success' => false,
'errors' => [
"You ve been locked out"
]
]);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
try{
if(!$token = $this->auth->attempt($request->only('email', 'password'))){
return response()->json([
'success' => false,
'errors' => [
'email' => [
"Invalid email address or password"
]
]
], 422);
}
} catch (JWTException $e){
return response()->json([
'success' => false,
'errors' => [
'email' => [
"Invalid email address or password"
]
]
], 422);
}
return response()->json([
'success' => true,
'data' => $request->user(),
'token' => $token
], 200);
}
}
ユーザ情報取得APIとログアウトAPIのコントローラを実装する
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Tymon\JWTAuth\JWTAuth;
class MeController extends Controller
{
protected $auth;
public function __construct(JWTAuth $auth)
{
$this->auth = $auth;
}
public function index(Request $request){
return response()->json([
'success' => true,
'data' => $request->user()
]);
}
public function logout()
{
auth()->logout();
return response()->json([
'success' => true,
]);
}
}
CORSの設定
CORSについてはここがわかりやすかったので見てみてください
Laravelではlaravel-corsという便利なモジュールがあるので今回はこれを使用します。
※本来は信頼できるドメインのみアクセス可能にするべきだが今回は全部のアクセスを許可するようにする
composer require barryvdh/laravel-cors
protected $middlewareGroups = [
...
'api' => [
'throttle:60,1',
'bindings',
\Barryvdh\Cors\HandleCors::class,
],
];
補足
実装の動画と多少変更してる箇所もあります。(ディレクトリ構成も変えてますが好みかなと思います)
例えば、api.php
の認可するためのmiddleware
はjwt.auth
にしてますが
現在のjwt-authのドキュメントは、auth.php
のguardsの設定を変更して
middleware
をapi:auth
にしてます。
正直どちらが正しいかはわからなかったのでもしわかる方は教えていただけると幸いです。