🤳
LaravelでDiscordと連携したユーザー仮登録機能を作ってみた
LaravelとDiscordを連携してユーザーの仮登録を行う機能を実装した話をまとめます。
実行環境
PHP 8.3
Laravel 11
MySQL 8.0
JavaScript (fetch API使用)
実装の流れ
- 新規登録画面でDiscord IDを入力
- 16桁の確認コードを生成
- DiscordのDMで確認コードを送信
- 確認コードと共に本登録画面へ遷移
- 確認コードを登録テーブルと照合して認証
マイグレーションとモデルの作成
Discord IDと登録コードを保存するテーブルを作成します。
php artisan make:model TempRegisterCode -m
マイグレーション
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
Schema::create('temp_register_codes', function (Blueprint $table) {
$table->id();
$table->string('discord_id')->comment('DiscordのID');
$table->string('register_code', 255)->comment('ハッシュ化をするため255文字にしておく');
$table->date('expires_at')->comment('有効期限(日付のみ)');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('temp_register_codes');
}
};
モデル
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TempRegisterCode extends Model
{
use HasFactory;
protected $table = 'temp_register_codes';
protected $fillable = [
'discord_id',
'register_code',
'expires_at',
];
protected $dates = ['expires_at'];
}
コントローラーからDiscordAPIを使用する
Discordに送信ボタンを押下するとAPIを叩きDiscordにbotからメッセージが来ます。
同時にDiscord IDと登録コードをテーブルに保存します。
public function sendDiscordRegisterCode(Request $request)
{
$discordId = $request['discord-ID'];
session(['discord_ID' => $discordId]);
//ランダムな16桁のコードを生成
$registerCode = substr(str_shuffle('1234567890abcdefghijklmnopqrstuvwxyz'), 0, self::LENGTH);
//ここでサービスを使用してランダムなコードをディスコードのidあてに送ります
$this->discordService->sendDiscordRegisterCode($discordId, $registerCode);
// 翌日の日付を取得
$expiresAt = $this->userService->getTomorrowDate();
// データを保存
$this->userService->createTempRegisterCode($discordId, $registerCode, $expiresAt);
//新規登録画面2を送る
return redirect()->route('register2', ['discord-ID' => $discordId]);
}
サービス
public function sendDiscordRegisterCode($discordUserId, $registerCode)
{
$message = "あなたの登録コードは `{$registerCode}` です。\n\n"
. "会員登録画面でこのコードを入力してください。\n"
. "コードの有効期限: 明日まで";
return $this->sendDirectMessage($discordUserId, $message);
}
public function sendDirectMessage($discordUserId, $message)
{
$channelId = $this->getDmChannelId($discordUserId);
if (!$channelId) {
Log::error("チャンネル ID の取得に失敗: ユーザーID {$discordUserId}");
}
$response = Http::withHeaders([
'Authorization' => 'Bot ' . $this->botToken,
'Content-Type' => 'application/json',
])->post("https://discord.com/api/v10/channels/{$channelId}/messages", [
'content' => $message,
]);
if (!$response->successful()) {
Log::error("メッセージ送信失敗: " . $response->body());
return [
'success' => false,
'message' => 'Discord へのメッセージ送信に失敗しました'
];
}
}
上記のようにしてDiscordに登録コードを送ります。
登録コードの検証
次の画面でユーザー情報とDiscord IDと登録コードを入力して送信します。
バリデーション
public function rules(): array
{
return [
'userid' => 'required|unique:users', // ユーザーIDが必須 & ユニーク
'term' => 'required|exists:terms,id', // term_idが存在するかチェック
'password' => 'required|min:8|confirmed', // 8文字以上 & 確認用と一致
'discord-ID' => 'required|string', // Discord ID は必須の文字列
'register-code' => [
'required',
'string',
'size:16',
new ValidDiscordRegisterCode // カスタムバリデーションを適用
],
'user-profile-image' => 'nullable|image|mimes:jpg,jpeg,png,gif|max:2048', // 画像は必須ではなく、最大2MBまで
];
}
Rules
今後再利用するかもしれないと考えカスタムバリデーションを使いました。
class ValidDiscordRegisterCode implements Rule
{
public function passes($attribute, $value)
{
// discord_idに基づいてすべてのレコードを取得
$tempRegisterCodes = TempRegisterCode::where('discord_id', request()->input('discord-ID'))->get();
// 取得したすべてのコードに対してチェック
foreach ($tempRegisterCodes as $tempRegisterCode) {
// ハッシュ化されたコードと入力されたコードを比較
if (Hash::check($value, $tempRegisterCode->register_code)) {
return true; // 一致したらtrueを返す
}
}
return false; // 一致しなければfalseを返す
}
public function message()
{
return 'Discord ID または 登録コードが無効です。';
}
}
また、カスタムバリデーションを使用したことでコードの可読性もあがりました。
上記のバリデーションが通ったらユーザー登録をするようなコードにしました。
まとめ
できたら便利だなと思っていたDiscordAPIを使用してみました。実際に使用できてとても感動しました!また、ロジックはサービスにまとめる、カスタムバリデーションを使用するなどコードをすっきり書き可読性を上げることもできました。今後もわかりやすくすっきりとしていながらもしっかりしたコードを書けるようにしたいです。
Discussion