【Laravel】Line Message APIのアカウント連携を制作してみた②
こんにちは。
ニシザワです。
Laravelを活用して、Line Message APIのアカウント連携をする方法について続きを書きたいと思います。
前回の記事はこちらです
【Laravel】Line Message APIのアカウント連携を制作してみた①
公式は こちら
Viewの実装(auth/login.blade.php
認証後はnonceを作成して、保存しておきます。
その後、認証完了のページへリダイレクトを送ります。
ですので、その情報をもとに、認証完了とします。
ApiController
最後に連携完了のメッセージを送っています。
連携までは以上になります。
次回は、連携解除を説明したいと思います。
追記 次回のの記事はこちらです
【Laravel】Line Message APIのアカウント連携を制作してみた③
ニシザワです。
Laravelを活用して、Line Message APIのアカウント連携をする方法について続きを書きたいと思います。
前回の記事はこちらです
【Laravel】Line Message APIのアカウント連携を制作してみた①
公式は こちら
Api\LoginControllerの実装
ログイン認証の表示と許可を実装します。ログインページ表示
Api\LoginController
use AuthenticatesUsers;
/**
* @param Request $request
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showLoginForm(Request $request){
if(\Auth::check()){
//ログイン状態だった場合強制ログアウトする
\Auth::logout();
}
$linkToken = $request->get("linkToken");
return view("auth.login", [
"linkToken" => $linkToken
]);
}
AuthenticatesUsersのトレイトを読み込んでおきましょう。Viewの実装(auth/login.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
@if(!empty($linkToken))
<form class="form-horizontal" method="POST" action="{{ route('api.login', ["linkToken" => $linkToken]) }}">
@else
<form class="form-horizontal" method="POST" action="{{ route('login') }}">
@endif
{{ csrf_field() }}
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password" required>
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-8 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Login
</button>
<a class="btn btn-link" href="{{ route('password.request') }}">
Forgot Your Password?
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
$linkTokenがある場合のみ、post先を変更します。
認証の実装
Api\LoginController
/**
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Symfony\Component\HttpFoundation\Response
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
$this->validateLogin($request);
if ($this->attemptLogin($request)) {
return $this->externalLine($request);
}
// 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);
return $this->sendFailedLoginResponse($request);
}
/**
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \Exception
*/
private function externalLine(Request $request){
$linkToken = $request->get("linkToken");
$nonce = \Hash::make(random_bytes(32));
$email = $request->get("email");
$user = User::query()->where("email", $email)->first();
$user->update([
"nonce" => $nonce,
]);
return Redirect("https://access.line.me/dialog/bot/accountLink?linkToken={$linkToken}&nonce={$nonce}");
}
基本的にはAuthenticatesUsersをフル活用して、認証部分を作ります。認証後はnonceを作成して、保存しておきます。
その後、認証完了のページへリダイレクトを送ります。
認証後の通知
認証完了ページへリダイレクトすると、認証完了のメッセージがwebhookに飛んできます。ですので、その情報をもとに、認証完了とします。
ApiController
/**
* @param Request $request
* @throws \LINE\LINEBot\Exception\CurlExecutionException
*/
public function webhook(Request $request){
$events = $request->get("events", []);
$userId = array_get($events, "0.source.userId");
$text = array_get($events, "0.message.text");
$replayToken = array_get($events, "0.replyToken");
$user = User::query()->where("uuid",$userId)->first();
//ここを追加
if(array_get($events, "0.link.result") === "ok"){
$this->saveAccount($events);
$httpClient = new \LINE\LINEBot\HTTPClient\CurlHTTPClient(config("auth.line-api-key"));
$bot = new \LINE\LINEBot($httpClient, ['channelSecret' => config("auth.channel-secret")]);
$textMessageBuilder = new \LINE\LINEBot\MessageBuilder\TextMessageBuilder("アカウントの連携に成功しました。");
$response = $bot->replyMessage($replayToken, $textMessageBuilder);
$lineResponse = $response->getHTTPStatus() . ' ' . $response->getRawBody();
\Log::info($lineResponse);
return;
}
//ここまで
//メッセージを送ったLineユーザーが連携していない場合
if(is_null($user) || is_null($user->nonce)){
$this->accountLink($userId, $replayToken);
return;
}
}
/**
* アカウント保存
* @param array $events
*/
private function saveAccount(array $events){
$uuid = array_get($events, "0.source.userId");
$nonce = array_get($events, "0.link.nonce");
$user = User::query()->where("nonce", $nonce)->first();
if(is_null($user)){
return;
}
$user->update([
"uuid" => $uuid
]);
}
resultがOKの場合のみ、uuidを保存して完了とします。最後に連携完了のメッセージを送っています。
連携までは以上になります。
次回は、連携解除を説明したいと思います。
追記 次回のの記事はこちらです
【Laravel】Line Message APIのアカウント連携を制作してみた③