脱初心者備忘録

Laravel Jetstreamで認証機能の実装

Laravel8 から、認証機能に Laravel Breeze・Laravel Jetstream・Laravel Fortify というスターターキットがリリースされました。
Composerでインストールするだけで使用が可能になります。
それぞれ、特徴があります。

  1. Laravel Breeze
    ログイン・登録・パスワードリセット・メール確認・パスワード確認などの認証機能が最小限で実装されています。
    bladeファイルは、Tailwind CSSで構成されています。
    VueやReactを使ったInertia.jsのフロントエンド実装も提供しています。
  2. Laravel Fortify
    Laravelのヘッドレス認証バックエンドであり、クッキーベースの認証や2要素認証、メールアドレス確認や他の機能など、多くの機能を実装しています。
    Laravel Sanctumと組み合わせて独立して使用できます。
  3. Laravel Jetstream
    Laravel Fortifyの認証サービスを使用し、2要素認証、チームサポート、ブラウザセッション管理、プロファイル管理、およびAPIトークン認証を提供するLaravel Sanctumとの組み込み統合が含まれています。
    フロント部分は、UIにTailwind CSSを使用したLivewireかInertia.jsを選択できます。

今回は、2要素認証(2段階認証)が組み込まれた、多機能なJetstreamを導入してみます。


【インストール環境】
Xampp
Windows10
PHP7.4

ComposerでJetstreamのインストール

Laravel8.x をインストールします。project_name は自分のプロジェクト名で。

composer create-project laravel/laravel:^8.0 --prefer-dist project_name


Laravelがインストールされたフォルダを、VSCodeで読み込みます。
Jetstreamのインストールは、Laravelのドキュメントサイトには、Jetsreamの公式ページを見ろと書いてあるので、そちらを開きます。

Laravel Jetstream 公式ページ

このページの中あたりに警告があります。
新規で作成されたLaravelの状態でインストールしてくださいとあります。

New Applications Only 

Jetstreamは、新しいLaravelアプリケーションにのみインストールする必要があります。 Jetstreamを既存のLaravelアプリケーションにインストールしようとすると、予期しない動作や問題が発生します。

Laravel Jetstream


VSCodeで新しいターミナルを立ち上げます。
下記のコードを入力します。

composer require laravel/jetstream

Livewire か Inertia を選ぶ

終わったら、ターミナルに次のコードを入力します。
ただし、Livewire か、Inertia を選んでインストールする必要があります。

  1. Livewire
    PHPのBladeを使用したライブラリ。Jsを利用しない。Vueが良くわからない人はこちら。
  2. Interia
    Vue.jsを使用したライブラリ。Vueが得意ならこちらがおすすめ。

自分はPHPerなので、LineWire一択。オプションで、–teams をつけることで、チームサポート機能が有効になります。

php artisan jetstream:install livewire --teams

NPMを使う

npm install して run して、アセットビルドしてねって言ってます。
ターミナルに入力します。

npm install

ここで結構待たされます。数十秒~通信状態によって数分。
あら、エラーです。

「注意を必要としない問題に対処するには、次のコマンドを実行します。
npm監査修正fix
すべての問題(重大な変更を含む)に対処するには、次のコマンドを実行します。
npm監査修正–force」
といった内容の脆弱性の警告です。35 vulnerabilities (2 low, 21 moderate, 12 high) で、12もの高いレベルでの脆弱性が見つかったよと警告しています。
ここで書かれている通り、forceをつけて、修正対応します。
ターミナルで記入します。

npm audit fix --force

「脆弱性は0件です」となったので安心して次に進みます。

次のコードを入力します。

npm run dev

はいまたエラー。hide-modules なんて知らないですって言ってます。
検索で探します。


VSCodeの左側に虫眼鏡のアイコンがあるので、それをクリックして、表示される検索窓に探したい単語を入力します。

package.jsonが見つかりました。
そのファイルから、–hide-modules を削除して、もう一度先ほどのコードを入力します。

npm run dev

次はうまくいきました。Laravel Mixが成功し無事コンパイルできました。

次はデータベースをmigrateします。

php artisan migrate

データベースに7つのテーブルが作成されました。

  • users
  • password_resets
  • failed_jobs
  • teams
  • team_user
  • team_invitations
  • sessions

Livewireスタックを使用している場合は、最初にLivewireスタックのBladeコンポーネントを公開する必要があります。

Laravel jetstream

上記に従って、次のコードをターミナルに入力します。

php artisan vendor:publish --tag=jetstream-views

viewsフォルダの中にvender\jetstreamが増え、componentフォルダとmailフォルダができています。
componentの中にはたくさんのパーツである、bladeファイルができました。

Register の WEB画面

サーバーを立ち上げて、画面の確認をします。

php artisan serve

http://localhost:8000

Login と Register のリンクができています。
最初は、Registerの画面から確認します。

BreezeのRegister画面と同じですね。
名前・メール・パスワードを登録するフォームです。

Breezeの時と同様に、日本語にできるところはしていきます。
resoucesフォルダの中にlangフォルダがあります。
enフォルダをコピーして、jaにリネームします。
さらに、langフォルダの下に、ja.jsonファイルを作成します。

ja.jsonには、以下の内容を記入します。

{
  "30 Days": "30日",
  "60 Days": "60日",
  "90 Days": "90日",
  ":amount Total": "合計:amount",
  ":days day trial": ":days日のトライアル",
  ":resource Details": ":resource詳細",
  ":resource Details: :title": ":resource詳細:title",
  "A new verification link has been sent to the email address you provided during registration.": "入力いただいたメールアドレスに新しい確認メールを送信しました。",
  "Accept Invitation": "招待を受け入れる",
  "Action": "演技はじめ!",
  "Action Happened At": "で起こった",
  "Action Initiated By": "によって開始",
  "Action Name": "名前",
  "Action Status": "ステータス",
  "Action Target": "ターゲット",
  "Actions": "アクション",
  "Add": "追加",
  "Add a new team member to your team, allowing them to collaborate with you.": "新しいチームメンバーを追加",
  "Add additional security to your account using two factor authentication.": "セキュリティ強化のため二段階認証を追加",
  "Add row": "行を追加",
  "Add Team Member": "チームメンバーを追加",
  "Add VAT Number": "VAT番号を追加",
  "Added.": "追加完了",
  "Address": "住所",
  "Address Line 2": "住所2",
  "Administrator": "管理者",
  "Administrator users can perform any action.": "管理者はすべてのアクションを実行可能です。",
  "All of the people that are part of this team.": "すべてのチームメンバー",
  "All resources loaded.": "すべてのリソースが読み込まれました。",
  "All rights reserved.": "All rights reserved.",
  "Already registered?": "登録済みの方はこちら",
  "American Samoa": "アメリカ領サモア",
  "An error occured while uploading the file.": "ファイルのアップロード中にエラーが発生しました。",
  "An unexpected error occurred and we have notified our support team. Please try again later.": "予期せぬエラーが発生しました。時間をおいてから改めてお試しください。",
  "Another user has updated this resource since this page was loaded. Please refresh the page and try again.": "ページが読み込まれてから他のユーザーがリソースを更新しました。ページを更新して、もう一度お試しください。",
  "API Token": "APIトークン",
  "API Token Permissions": "APIトークン認可",
  "API Tokens": "APIトークン",
  "API tokens allow third-party services to authenticate with our application on your behalf.": "APIトークンを使うとサードパーティーのサービスからアプリへの認証ができるようになります。",
  "Apply": "Apply",
  "Apply Coupon": "Apply Coupon",
  "April": "4月",
  "Are you sure you want to delete the selected resources?": "選択したリソースを削除しますか?",
  "Are you sure you want to delete this file?": "このファイルを削除しますか?",
  "Are you sure you want to delete this resource?": "このリソースを削除しますか?",
  "Are you sure you want to delete this team? Once a team is deleted, all of its resources and data will be permanently deleted.": "チームを削除しますか?チームを削除すると、すべてのデータが完全に削除されます。",
  "Are you sure you want to delete your account? Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.": "アカウントを削除しますか?アカウントを削除するとすべてのデータが完全に削除されます。よろしければパスワードを入力してください。",
  "Are you sure you want to detach the selected resources?": "選択したリソースを解除しますか?",
  "Are you sure you want to detach this resource?": "このリソースを解除しますか?",
  "Are you sure you want to force delete the selected resources?": "選択したリソースを強制的に削除しますか?",
  "Are you sure you want to force delete this resource?": "このリソースを強制的に削除しますか?",
  "Are you sure you want to restore the selected resources?": "選択したリソースを復元しますか?",
  "Are you sure you want to restore this resource?": "このリソースを復元しますか?",
  "Are you sure you want to run this action?": "このアクションを実行しますか?",
  "Are you sure you would like to delete this API token?": "APIトークンを削除しますか?",
  "Are you sure you would like to leave this team?": "このチームを離れますか?",
  "Are you sure you would like to remove this person from the team?": "このメンバーをチームから削除しますか?",
  "Attach": "添付",
  "Attach & Attach Another": "添付して新しく添付",
  "Attach :resource": ":resourceを添付",
  "August": "8月",
  "Billing Information": "Billing Information",
  "Billing Management": "Billing Management",
  "Browser Sessions": "ブラウザセッション",
  "Cancel": "キャンセル",
  "Cancel Subscription": "プランをキャンセル",
  "Cape Verde": "カーボベルデ",
  "Card": "カード",
  "Change Subscription Plan": "プランを変更",
  "Changes": "変更点",
  "Choose": "選択",
  "Choose :field": ":fieldを選択",
  "Choose :resource": ":resourceを選択",
  "Choose an option": "オプションを選択する",
  "Choose date": "日付を選択",
  "Choose File": "ファイルを選択",
  "Choose Type": "タイプを選択",
  "City": "市区町村",
  "Click to choose": "クリックして選択する",
  "Close": "閉じる",
  "Code": "コード",
  "Confirm": "確認",
  "Confirm Password": "パスワード(確認用)",
  "Confirm Payment": "お支払いの確認",
  "Confirm your :amount payment": ":amount 個のお支払いを確認",
  "Constant": "定数",
  "could not be found.": "見つかりませんでした。",
  "Country": "国",
  "Coupon": "クーポン",
  "Create": "作成",
  "Create & Add Another": "作成して新しく追加する",
  "Create :resource": ":resourceを作成",
  "Create a new team to collaborate with others on projects.": "新しいチームを作って、共同でプロジェクトを進める。",
  "Create Account": "アカウントの作成",
  "Create API Token": "APIトークン生成",
  "Create New Team": "新しいチームを作成",
  "Create Team": "チームを作成",
  "Created.": "作成しました",
  "Current Password": "現在のパスワード",
  "Current Subscription Plan": "現在のプラン",
  "Currently Subscribed": "現在購読している",
  "Customize": "カスタマイズ",
  "Dashboard": "ダッシュボード",
  "December": "12月",
  "Decrease": "減少",
  "Delete": "削除",
  "Delete Account": "アカウント削除",
  "Delete API Token": "APIトークン削除",
  "Delete File": "ファイル削除",
  "Delete Resource": "リソース削除",
  "Delete Selected": "選択した内容を削除",
  "Delete Team": "チームを削除",
  "Detach": "解除",
  "Detach Resource": "リソースを解除",
  "Detach Selected": "選択した内容を解除",
  "Details": "詳細",
  "Disable": "無効化",
  "Do you really want to leave? You have unsaved changes.": "保存されていない変更があります。離れますか?",
  "Done.": "完了",
  "Download": "ダウンロード",
  "Download Receipt": "領収書をダウンロード",
  "Edit": "編集",
  "Edit :resource": ":resourceを編集",
  "Edit Attached": "添付を編集",
  "Editor": "編集者",
  "Editor users have the ability to read, create, and update.": "編集者は読み込み、作成、更新ができます。",
  "Email": "メールアドレス",
  "Email Address": "メールアドレス",
  "Email Addresses": "メールアドレス",
  "Email Password Reset Link": "送信",
  "Enable": "有効化",
  "Ensure your account is using a long, random password to stay secure.": "長くてランダムなパスワードを設定してください。",
  "ex VAT": "ex VAT",
  "Extra Billing Information": "Extra Billing Information",
  "Extra confirmation is needed to process your payment. Please confirm your payment by filling out your payment details below.": "お支払いを完了するには、追加の確認が必要です。以下のお支払い詳細をご記入の上、お支払いを確認してください。",
  "Extra confirmation is needed to process your payment. Please continue to the payment page by clicking on the button below.": "お支払いを完了するには、追加の確認が必要です。以下のボタンをクリックして、お支払いページに進んでください。",
  "February": "2月",
  "For your security, please confirm your password to continue.": "安全のため、パスワードを入力して続行ください。",
  "Forbidden": "禁止されています",
  "Force Delete": "強制的に削除する",
  "Force Delete Resource": "リソースを強制的に削除する",
  "Force Delete Selected": "選択した内容を強制的に削除する",
  "Forgot your password?": "パスワードを忘れた方はこちら",
  "Forgot Your Password?": "パスワードを忘れた方はこちら",
  "Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.": "ご登録いただいたメールアドレスを入力してください。パスワード再設定用のURLをメールにてお送りします。",
  "Full name": "フルネーム",
  "Go back": "戻る",
  "Go Home": "ホームへ",
  "Go to page :page": ":pageページへ",
  "Great! You have accepted the invitation to join the :team team.": ":teamチームに参加しました。",
  "Have a coupon code?": "クーポンコードをお持ちの場合",
  "Having second thoughts about cancelling your subscription? You can instantly reactive your subscription at any time until the end of your current billing cycle. After your current billing cycle ends, you may choose an entirely new subscription plan.": "有効期間内であればいつでもプランを再開できます。有効期限を過ぎた際には新しくプランに登録し直す必要があります。",
  "Hello!": "ご利用ありがとうございます。",
  "Hide Content": "コンテンツを非表示",
  "Hold Up!": "お待ちください",
  "I accept the terms of service": "利用規約に同意します",
  "I agree to the :terms_of_service and :privacy_policy": ":terms_of_serviceと:privacy_policyに同意します",
  "ID": "ID",
  "If necessary, you may log out of all of your other browser sessions across all of your devices. Some of your recent sessions are listed below; however, this list may not be exhaustive. If you feel your account has been compromised, you should also update your password.": "お使いのすべての端末からログアウトできます。最近のセッションは下記の通りです(一部の情報が表示されていない可能性があります)。心配に応じてパスワードの更新もご検討ください。",
  "If you already have an account, you may accept this invitation by clicking the button below:": "アカウントがすでにある場合は、以下のボタンをクリックして招待を承認できます:",
  "If you did not create an account, no further action is required.": "アカウントの作成にお心当たりがない場合は、このメールを無視してください。",
  "If you did not expect to receive an invitation to this team, you may discard this email.": "この招待メールにお心当たりがない場合は、このメールを無視してください。",
  "If you did not request a password reset, no further action is required.": "パスワード再設定のリクエストにお心当たりがない場合は、このメールを無視してください。",
  "If you do not have an account, you may create one by clicking the button below. After creating an account, you may click the invitation acceptance button in this email to accept the team invitation:": "アカウントをお持ちでない場合は、以下のボタンをクリックしてアカウントを作成できます。アカウント作成後は招待メールのリンクをクリックして登録を完了してください。",
  "If you need to add specific contact or tax information to your receipts, like your full business name, VAT identification number, or address of record, you may add it here.": "領収書に社名や住所など追加の情報を記載する場合はこちらに記入してください。",
  "If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": " \":actionText\" ボタンをクリックできない場合は、以下のURLをコピーしてWebブラウザに貼り付けてください。:",
  "Increase": "増やす",
  "It looks like you do not have an active subscription. You may choose one of the subscription plans below to get started. Subscription plans may be changed or cancelled at your convenience.": "有効なサブスクリプションがありません。以下のプランの中から1つを選んで続けてください。プランはいつでも変更やキャンセルができます。",
  "Jane Doe": "Jane Doe",
  "January": "1月",
  "Japan": "日本",
  "July": "7月",
  "June": "6月",
  "Key": "キー",
  "Last active": "最後のログイン",
  "Last used": "最後に使用された",
  "Leave": "離れる",
  "Leave Team": "チームを離れる",
  "Load :perPage More": ":perPageページ分読み込む",
  "Log in": "ログイン",
  "Log Out": "ログアウト",
  "Log Out Other Browser Sessions": "すべての端末からログアウト",
  "Login": "ログイン",
  "Logout": "ログアウト",
  "Mali": "小さい",
  "Manage Account": "アカウント管理",
  "Manage and log out your active sessions on other browsers and devices.": "すべての端末からログアウトする。",
  "Manage API Tokens": "APIトークン管理",
  "Manage Role": "役割管理",
  "Manage Team": "チーム管理",
  "Managing billing for :billableName": ":billableNameの支払いを管理",
  "March": "3月",
  "May": "5月",
  "Micronesia, Federated States of": "Micronesia, Federated States of",
  "Month To Date": "月",
  "Monthly": "月",
  "monthly": "月",
  "Name": "お名前",
  "Nevermind, I'll keep my old plan": "以前のプランを維持します。",
  "New": "新しい",
  "New :resource": "新:resource",
  "New Password": "新しいパスワード",
  "Next": "次へ",
  "No": "いいえ。",
  "No :resource matched the given criteria.": ":resourceは与えられた基準に一致しませんでした。",
  "No additional information...": "追加情報はありません。..",
  "No Current Data": "現在のデータなし",
  "No Data": "データなし",
  "no file selected": "ファイルが選択されていません",
  "No Increase": "増加なし",
  "No Prior Data": "事前データなし",
  "No Results Found.": "結果は見つかりませんでした。",
  "Not Found": "見つかりません",
  "Nova User": "Novaユーザー",
  "November": "11月",
  "October": "10月",
  "of": "の",
  "Oh no": "オーノー",
  "Once a team is deleted, all of its resources and data will be permanently deleted. Before deleting this team, please download any data or information regarding this team that you wish to retain.": "アカウントを削除すると、すべてのデータが完全に削除されます。削除する前に、保存しておきたいデータなどはダウンロードしてください。",
  "Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.": "アカウントを削除すると、すべてのデータが完全に削除されます。削除する前に、保存しておきたいデータなどはダウンロードしてください。",
  "Only Trashed": "ゴミ箱のみ",
  "Original": "オリジナル",
  "Our billing management portal allows you to conveniently manage your subscription plan, payment method, and download your recent invoices.": "支払いの管理ポータルではプランやお支払い方法の変更、請求書のダウンロードができます。",
  "Page Expired": "ページが無効です",
  "Pagination Navigation": "ページネーション",
  "Password": "パスワード",
  "Pay :amount": ":amount円",
  "Payment Cancelled": "支払いキャンセル",
  "Payment Confirmation": "お支払いの確認",
  "Payment Information": "お支払い方法",
  "Payment Method": "Payment Method",
  "Payment Successful": "支払いが成功した",
  "Pending Team Invitations": "保留中のチーム招待",
  "Per Page": "ページごと",
  "Permanently delete this team.": "永久にチームを削除する。",
  "Permanently delete your account.": "永久にアカウントを削除する。",
  "Permissions": "認可",
  "Photo": "写真",
  "Please accept the terms of service.": "利用規約に同意してください。",
  "Please click the button below to verify your email address.": "メールアドレスを確認してアカウントを有効にするには、以下のボタンをクリックしてください。",
  "Please confirm access to your account by entering one of your emergency recovery codes.": "アカウントへアクセスするには、リカバリーコードを1つ入力してください。",
  "Please confirm access to your account by entering the authentication code provided by your authenticator application.": "認証アプリから提供された認証コードを入力し、アカウントへのアクセスを確認してください。",
  "Please copy your new API token. For your security, it won't be shown again.": "新しいAPIトークンをコピーしてください。安全のため、二度と表示されません。",
  "Please enter your password to confirm you would like to log out of your other browser sessions across all of your devices.": "すべての端末からログアウトします。よろしければパスワードを入力してください。",
  "Please provide a maximum of three receipt emails addresses.": "領収書発行用メールアドレスを最大3つまで入力してください。",
  "Please provide the email address of the person you would like to add to this team.": "このチームに追加したい人のメールアドレスを入力してください。",
  "Please provide your name.": "お名前をご記入ください。",
  "Press \/ to search": "押して検索",
  "Preview": "プレビュー",
  "Previous": "前のページ",
  "Privacy Policy": "プライバシーポリシー",
  "Profile": "プロフィール",
  "Profile Information": "プロフィール情報",
  "Quarter To Date": "四半期",
  "Receipt Email Addresses": "領収書発行用メールアドレス",
  "Receipts": "領収書",
  "Recovery Code": "リカバリーコード",
  "Regards": "よろしくお願いします",
  "Regenerate Recovery Codes": "リカバリーコード再生成",
  "Register": "アカウント作成",
  "Reload": "リロード",
  "Remember me": "ログイン状態を保持する",
  "Remember Me": "ログイン状態を保持する",
  "Remove": "削除",
  "Remove Photo": "写真を削除",
  "Remove Team Member": "チームメンバーを削除",
  "Resend Verification Email": "確認メールを再送する",
  "Reset Filters": "フィルタをリセット",
  "Reset Password": "パスワード再設定",
  "Reset Password Notification": "パスワード再設定のお知らせ",
  "resource": "リソース",
  "Resources": "リソース",
  "resources": "リソース",
  "Restore": "復元",
  "Restore Resource": "リソースの復元",
  "Restore Selected": "選択した項目を復元",
  "results": "結果",
  "Resume Subscription": "サブスクリプションを再開",
  "Return to :appName": ":appNameに戻る",
  "Reunion": "打合せ",
  "Role": "役割",
  "Run Action": "アクションを実行",
  "Save": "更新",
  "Saved.": "更新完了",
  "Search": "検索",
  "Select": "選択",
  "Select a different plan": "別のプランを選択",
  "Select A New Photo": "新しい写真を選択",
  "Select Action": "選択アクション",
  "Select All": "すべて選択",
  "Select All Matching": "一致するすべてを選択",
  "Send Password Reset Link": "パスワード再設定URLを送信",
  "September": "9月",
  "Server Error": "サーバーエラー",
  "Service Unavailable": "サービスは利用できません",
  "Seychelles": "セーシェル",
  "Show All Fields": "すべての項目を表示",
  "Show Content": "コンテンツを表示",
  "Show Recovery Codes": "リカバリーコードを表示",
  "Showing": "表示",
  "Signed in as": "Signed in as",
  "Something went wrong.": "エラーが発生しました。",
  "Sorry! You are not authorized to perform this action.": "このアクションを実行する権限がありません。",
  "Sorry, your session has expired.": "セッションが終了しました。",
  "Standalone Actions": "Standalone Actions",
  "Start Polling": "ポーリング開始",
  "State \/ County": "州",
  "Stop Polling": "ポーリングの停止",
  "Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.": "パスワード管理ツールにリカバリーコードを保存してください。二段階認証に使用する端末を紛失した場合にリカバリーコードを使ってログインできます。",
  "Subscribe": "購読する",
  "Subscription Information": "サブスクリプション情報",
  "Subscription Pending": "Subscription Pending",
  "Switch Teams": "チーム切り替え",
  "Team Details": "チーム詳細",
  "Team Invitation": "チーム招待",
  "Team Members": "チームメンバー",
  "Team Name": "チーム名",
  "Team Owner": "チームオーナー",
  "Team Settings": "チーム設定",
  "Terms of Service": "利用規約",
  "Thailand": "タイ",
  "Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn't receive the email, we will gladly send you another.": "ご登録ありがとうございます。入力いただいたメールアドレス宛にを確認のメールを送信しました。メールをご確認いただき、メールに記載されたURLをクリックして登録を完了してください。メールが届かない場合、メールを再送できます。",
  "Thanks for your continued support. We've attached a copy of your invoice for your records. Please let us know if you have any questions or concerns.": "継続した支援をありがとうございます。請求書のコピーをレコードに添付しました。ご不明点があればお問い合わせください。",
  "Thanks,": "Thanks,",
  "The :attribute must be a valid role.": ":attributeは有効なロールである必要があります。",
  "The :attribute must be at least :length characters and contain at least one number.": ":attributeは:length文字以上で、数字を1文字以上含めなければなりません。",
  "The :attribute must be at least :length characters and contain at least one special character and one number.": ":attributeは:length文字以上で、記号と数字をそれぞれ1文字以上含めなければなりません。。",
  "The :attribute must be at least :length characters and contain at least one special character.": ":attributeは:length文字以上で、記号を1文字以上含めなければなりません。",
  "The :attribute must be at least :length characters and contain at least one uppercase character and one number.": ":attributeは:length文字以上で、大文字と数字をそれぞれ1文字以上含めなければなりません。",
  "The :attribute must be at least :length characters and contain at least one uppercase character and one special character.": ":attributeは:length文字以上で、大文字と記号をそれぞれ1文字以上含めなければなりません。",
  "The :attribute must be at least :length characters and contain at least one uppercase character, one number, and one special character.": ":attributeは:length文字以上で、大文字・数字・記号をそれぞれ1文字以上含めなければなりません。",
  "The :attribute must be at least :length characters and contain at least one uppercase character.": ":attributeは:length文字以上で、大文字を1文字以上含めなければなりません。",
  "The :attribute must be at least :length characters.": ":attributeは:length文字以上でなければなりません。",
  "The :attribute must contain at least one letter.": ":attributeは文字を1文字以上含めなければなりません。",
  "The :attribute must contain at least one number.": ":attributeは数字を1文字以上含めなければなりません。",
  "The :attribute must contain at least one symbol.": ":attributeは記号を1文字以上含めなければなりません。",
  "The :attribute must contain at least one uppercase and one lowercase letter.": ":attributeは大文字と小文字をそれぞれ1文字以上含めなければなりません。",
  "The :resource was created!": ":resourceが作成されました。",
  "The :resource was deleted!": ":resourceが削除されました。",
  "The :resource was restored!": ":resourceが復元されました。",
  "The :resource was updated!": ":resourceが更新されました。",
  "The action ran successfully!": "アクションは成功しました。",
  "The file was deleted!": "ファイルが削除されました。",
  "The given :attribute has appeared in a data leak. Please choose a different :attribute.": ":attributeはデータ漏洩の対象だった可能性があります。別の:attributeを選んでください。",
  "The government won't let us show you what's behind these doors": "政府はこれらのドアの背後にあるものをお見せさせません",
  "The HasOne relationship has already been filled.": "HasOneの関係はすでに満たされています。",
  "The password is incorrect.": "The password is incorrect.",
  "The payment was successful.": "支払いは成功しました。",
  "The provided coupon code is invalid.": "クーポンコードが無効です。",
  "The provided password does not match your current password.": "パスワードが現在のパスワードと一致しません。",
  "The provided password was incorrect.": "パスワードが違います。",
  "The provided two factor authentication code was invalid.": "提供された二段階認証コードが無効です。",
  "The provided VAT number is invalid.": "VAT番号が無効です。",
  "The receipt emails must be valid email addresses.": "有効なメールアドレスを入力してください。",
  "The resource was updated!": "リソースが更新されました。",
  "The selected country is invalid.": "選択された国が無効です。",
  "The selected plan is invalid.": "選択されたプランが無効です。",
  "The team's name and owner information.": "チーム名とオーナー情報",
  "There are no available options for this resource.": "このリソースに使用可能なオプションはありません。",
  "There is no active subscription.": "There is no active subscription.",
  "There was a problem executing the action.": "アクションの実行に問題がありました。",
  "There was a problem submitting the form.": "フォームの送信に問題がありました。",
  "These people have been invited to your team and have been sent an invitation email. They may join the team by accepting the email invitation.": "これらのユーザー宛にチームへの招待メールが送信されました。招待メールを確認してチームに参加できます。",
  "This account does not have an active subscription.": "このアカウントには有効なサブスクリプションがありません。",
  "This action is unauthorized.": "この操作は許可されていません。",
  "This device": "この端末",
  "This file field is read-only.": "このfileフィールドは読み取り専用です。",
  "This image": "この画像",
  "This is a secure area of the application. Please confirm your password before continuing.": "ここはアプリケーションのセキュアな領域です。パスワードを入力して続行ください。",
  "This password does not match our records.": "パスワードが違います。",
  "This password reset link will expire in :count minutes.": "このパスワード再設定リンクの有効期限は:count分です。",
  "This payment was already successfully confirmed.": "この支払いはすでに正常に確認されました。",
  "This payment was cancelled.": "この支払いは取り消された。",
  "This resource no longer exists": "このリソースは存在しません",
  "This subscription cannot be resumed. Please create a new subscription.": "This subscription cannot be resumed. Please create a new subscription.",
  "This subscription has expired and cannot be resumed. Please create a new subscription.": "このサブスクリプションは有効期限を過ぎており再開できません。新しいサブスクリプションを作成してください。",
  "This user already belongs to the team.": "このユーザーは既にチームに所属しています。",
  "This user has already been invited to the team.": "このユーザーは既にチームに招待されています。",
  "to": "に",
  "Today": "今日は",
  "Toggle navigation": "ナビゲーションを切り替える",
  "Togo": "トーゴ",
  "Token Name": "トークン名",
  "Tonga": "トンガ",
  "Too Many Requests": "リクエストが多すぎます",
  "total": "合計",
  "Total:": "合計:",
  "Trashed": "ゴミ箱",
  "Tuvalu": "ツバル",
  "Two Factor Authentication": "二段階認証",
  "Two factor authentication is now enabled. Scan the following QR code using your phone's authenticator application.": "二段階認証を有効化しました。QRコードをアプリからスキャンしてください。",
  "Unauthorized": "認証が必要です",
  "Update": "更新",
  "Update & Continue Editing": "更新して編集を続ける",
  "Update :resource": ":resource更新",
  "Update :resource: :title": ":resource::title",
  "Update attached :resource: :title": "アップデート添付:resource::title",
  "Update Password": "パスワード更新",
  "Update Payment Information": "お支払い方法を更新",
  "Update Payment Method": "Update Payment Method",
  "Update your account's profile information and email address.": "プロフィール情報とメールアドレスを更新する。",
  "Uruguay": "ウルグアイ",
  "Use a recovery code": "リカバリーコードを使用する",
  "Use an authentication code": "認証コードを使用する",
  "UserName": "ユーザー名",
  "Value": "値",
  "VAT Number": "VAT番号",
  "Verify Email Address": "メールアドレスを確認する",
  "View": "ビュー",
  "View Receipt": "View Receipt",
  "We are processing your subscription. Once the subscription has successfully processed, this page will update automatically. Typically, this process should only take a few seconds.": "サブスクリプションを処理しています。 サブスクリプションが正常に処理されると、このページは自動的に更新されます。 通常、このプロセスには数秒しかかかりません。",
  "We are unable to process your payment. Please contact customer support.": "決済が完了できませんでした。カスタマーサポートへお問い合わせください。",
  "We were unable to find a registered user with this email address.": "このメールアドレスは登録されていません。",
  "We will send a receipt download link to the email addresses that you specify below. You may separate multiple email addresses using commas.": "領収書のダウンロードURLを以下のメールアドレスにお送りします。カンマ区切りで複数のメールアドレスの指定が可能です。",
  "We're lost in space. The page you were trying to view does not exist.": "お探しのページが見つかりませんでした。",
  "Welcome Back!": "おかえりなさい。",
  "Western Sahara": "西サハラ",
  "When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.": "二段階認証を有効化した場合、ログイン時に安全かつランダムなトークンが与えられます。トークンはGoogle Authenticatorアプリから取得できます。",
  "Whoops": "おっと",
  "Whoops!": "おっと!",
  "Whoops! Something went wrong.": "エラーの内容を確認してください。",
  "With Trashed": "ゴミ箱付き",
  "Write": "書き込み",
  "Year To Date": "年から現在に至るまで",
  "Yearly": "年",
  "Yes": "はい。",
  "You are already subscribed.": "あなたはすでに加入しています。",
  "You are currently within your free trial period. Your trial will expire on :date.": "現在トライアル期間です。トライアル期間は:dateまでです。",
  "You are receiving this email because we received a password reset request for your account.": "パスワード再設定のリクエストを受け付けました。",
  "You have been invited to join the :team team!": ":teamに招待されました。",
  "You have enabled two factor authentication.": "二段階認証が有効です。",
  "You have not enabled two factor authentication.": "二段階認証が未設定です。",
  "You may accept this invitation by clicking the button below:": "You may accept this invitation by clicking the button below:",
  "You may cancel your subscription at any time. Once your subscription has been cancelled, you will have the option to resume the subscription until the end of your current billing cycle.": "サブスクリプションはいつでもキャンセルできます。キャンセルする際は次回お支払い日まで利用を続けるかどうかを選択できます。",
  "You may delete any of your existing tokens if they are no longer needed.": "不要なAPIトークンを削除する。",
  "You may not delete your personal team.": "パーソナルチームを削除することはできません。",
  "You may not leave a team that you created.": "自身が作成したチームを離れることはできません。",
  "Your :invoiceName invoice is now available!": ":invoiceNameの請求書がご利用可能です。",
  "Your card was declined. Please contact your card issuer for more information.": "カードが拒否されました。詳細はカード発行会社にお問い合わせください。",
  "Your current payment method is :paypal.": "現在のお支払い方法: :paypal.",
  "Your current payment method is a credit card ending in :lastFour that expires on :expiration.": "現在のお支払い方法は下4桁が:lastFour、有効期限が:expirationのクレジットカードです。",
  "Your registered VAT Number is :vatNumber.": "登録されているVAT番号は:vatNumberです。",
  "Zip \/ Postal Code": "郵便番号"
}

jaフォルダの中身を修正します。

//ja\auth.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */

    'failed' => '登録情報と一致しません。',
    'password' => 'パスワードが正しくありません。',
    'throttle' => 'ログイン試行回数が多すぎます。 :seconds 秒後に再試行してください。',

];
//ja\pagination.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Pagination Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used by the paginator library to build
    | the simple pagination links. You are free to change them to anything
    | you want to customize your views to better match your application.
    |
    */
    
    'previous' => '&laquo; 前',
    'next' => '次 &raquo;',

];
//ja\passwords.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Password Reset Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are the default lines which match reasons
    | that are given by the password broker for a password update attempt
    | has failed, such as for an invalid token or invalid new password.
    |
    */

    'reset' => 'パスワードはリセットされました!',
    'sent' => 'パスワードリセットリンクをメールで送信しました!',
    'throttled' => '時間を置いて再度お試しください。',
    'token' => 'このパスワードリセットトークンは無効です。',
    'user' => "そのメールアドレスのユーザーが見つかりません。",

];
//ja\validation.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines contain the default error messages used by
    | the validator class. Some of these rules have multiple versions such
    | as the size rules. Feel free to tweak each of these messages here.
    |
    */

    'accepted'             => ':attributeを承認してください。',
    'accepted_if'          => 'The :attribute must be accepted when :other is :value.',
    'active_url'           => ':attributeは、有効なURLではありません。',
    'after'                => ':attributeには、:dateより後の日付を指定してください。',
    'after_or_equal'       => ':attributeには、:date以降の日付を指定してください。',
    'alpha'                => ':attributeには、アルファベッドのみ使用できます。',
    'alpha_dash'           => ':attributeには、英数字(\'A-Z\',\'a-z\',\'0-9\')とハイフンと下線(\'-\',\'_\')が使用できます。',
    'alpha_num'            => ':attributeには、英数字(\'A-Z\',\'a-z\',\'0-9\')が使用できます。',
    'array'                => ':attributeには、配列を指定してください。',
    'attached'             => 'この:attributeはすでに添付されています。',
    'before'               => ':attributeには、:dateより前の日付を指定してください。',
    'before_or_equal'      => ':attributeには、:date以前の日付を指定してください。',
    'between'              => [
        'array'   => ':attributeの項目は、:min個から:max個にしてください。',
        'file'    => ':attributeには、:min KBから:max KBまでのサイズのファイルを指定してください。',
        'numeric' => ':attributeには、:minから、:maxまでの数字を指定してください。',
        'string'  => ':attributeは、:min文字から:max文字にしてください。',
    ],
    'boolean'              => ':attributeには、\'true\'か\'false\'を指定してください。',
    'confirmed'            => ':attributeと:attribute確認が一致しません。',
    'current_password'     => 'The password is incorrect.',
    'date'                 => ':attributeは、正しい日付ではありません。',
    'date_equals'          => ':attributeは:dateに等しい日付でなければなりません。',
    'date_format'          => ':attributeの形式は、\':format\'と合いません。',
    'different'            => ':attributeと:otherには、異なるものを指定してください。',
    'digits'               => ':attributeは、:digits桁にしてください。',
    'digits_between'       => ':attributeは、:min桁から:max桁にしてください。',
    'dimensions'           => ':attributeの画像サイズが無効です',
    'distinct'             => ':attributeの値が重複しています。',
    'email'                => ':attributeは、有効なメールアドレス形式で指定してください。',
    'ends_with'            => ':attributeは、次のうちのいずれかで終わらなければなりません。: :values',
    'exists'               => '選択された:attributeは、有効ではありません。',
    'file'                 => ':attributeはファイルでなければいけません。',
    'filled'               => ':attributeは必須です。',
    'gt'                   => [
        'array'   => ':attributeの項目数は、:value個より大きくなければなりません。',
        'file'    => ':attributeは、:value KBより大きくなければなりません。',
        'numeric' => ':attributeは、:valueより大きくなければなりません。',
        'string'  => ':attributeは、:value文字より大きくなければなりません。',
    ],
    'gte'                  => [
        'array'   => ':attributeの項目数は、:value個以上でなければなりません。',
        'file'    => ':attributeは、:value KB以上でなければなりません。',
        'numeric' => ':attributeは、:value以上でなければなりません。',
        'string'  => ':attributeは、:value文字以上でなければなりません。',
    ],
    'image'                => ':attributeには、画像を指定してください。',
    'in'                   => '選択された:attributeは、有効ではありません。',
    'in_array'             => ':attributeが:otherに存在しません。',
    'integer'              => ':attributeには、整数を指定してください。',
    'ip'                   => ':attributeには、有効なIPアドレスを指定してください。',
    'ipv4'                 => ':attributeはIPv4アドレスを指定してください。',
    'ipv6'                 => ':attributeはIPv6アドレスを指定してください。',
    'json'                 => ':attributeには、有効なJSON文字列を指定してください。',
    'lt'                   => [
        'array'   => ':attributeの項目数は、:value個より小さくなければなりません。',
        'file'    => ':attributeは、:value KBより小さくなければなりません。',
        'numeric' => ':attributeは、:valueより小さくなければなりません。',
        'string'  => ':attributeは、:value文字より小さくなければなりません。',
    ],
    'lte'                  => [
        'array'   => ':attributeの項目数は、:value個以下でなければなりません。',
        'file'    => ':attributeは、:value KB以下でなければなりません。',
        'numeric' => ':attributeは、:value以下でなければなりません。',
        'string'  => ':attributeは、:value文字以下でなければなりません。',
    ],
    'max'                  => [
        'array'   => ':attributeの項目は、:max個以下にしてください。',
        'file'    => ':attributeには、:max KB以下のファイルを指定してください。',
        'numeric' => ':attributeには、:max以下の数字を指定してください。',
        'string'  => ':attributeは、:max文字以下にしてください。',
    ],
    'mimes'                => ':attributeには、:valuesタイプのファイルを指定してください。',
    'mimetypes'            => ':attributeには、:valuesタイプのファイルを指定してください。',
    'min'                  => [
        'array'   => ':attributeの項目は、:min個以上にしてください。',
        'file'    => ':attributeには、:min KB以上のファイルを指定してください。',
        'numeric' => ':attributeには、:min以上の数字を指定してください。',
        'string'  => ':attributeは、:min文字以上にしてください。',
    ],
    'mixedcase' => ':attributeには、少なくとも1つの大文字と1つの小文字が含まれている必要があります。',
    'multiple_of'          => ':attributeは:valueの倍数でなければなりません',
    'not_in'               => '選択された:attributeは、有効ではありません。',
    'not_regex'            => ':attributeの形式が無効です。',
    'numeric'              => ':attributeには、数字を指定してください。',
    'password'             => 'パスワードが正しくありません。',
    'present'              => ':attributeが存在している必要があります。',
    'prohibited'           => ':attributeフィールドは禁止されています。',
    'prohibited_if'        => ':attributeフィールドは、:otherが:valueの場合は禁止されています。',
    'prohibited_unless'    => ':attributeフィールドは、:otherが:valuesでない限り禁止されています。',
    'prohibits'            => 'The :attribute field prohibits :other from being present.',
    'regex'                => ':attributeには、有効な正規表現を指定してください。',
    'relatable'            => 'この:attributeきない場合に伴い資源です。',
    'required'             => ':attributeは、必ず指定してください。',
    'required_if'          => ':otherが:valueの場合、:attributeを指定してください。',
    'required_unless'      => ':otherが:values以外の場合、:attributeを指定してください。',
    'required_with'        => ':valuesが指定されている場合、:attributeも指定してください。',
    'required_with_all'    => ':valuesが全て指定されている場合、:attributeも指定してください。',
    'required_without'     => ':valuesが指定されていない場合、:attributeを指定してください。',
    'required_without_all' => ':valuesが全て指定されていない場合、:attributeを指定してください。',
    'same'                 => ':attributeと:otherが一致しません。',
    'size'                 => [
        'array'   => ':attributeの項目は、:size個にしてください。',
        'file'    => ':attributeには、:size KBのファイルを指定してください。',
        'numeric' => ':attributeには、:sizeを指定してください。',
        'string'  => ':attributeは、:size文字にしてください。',
    ],
    'starts_with'          => ':attributeは、次のいずれかで始まる必要があります。:values',
    'string'               => ':attributeには、文字を指定してください。',
    'timezone'             => ':attributeには、有効なタイムゾーンを指定してください。',
    'unique'               => '指定の:attributeは既に使用されています。',
    'uploaded'             => ':attributeのアップロードに失敗しました。',
    'url'                  => ':attributeは、有効なURL形式で指定してください。',
    'uuid'                 => ':attributeは、有効なUUIDでなければなりません。',

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | Here you may specify custom validation messages for attributes using the
    | convention "attribute.rule" to name the lines. This makes it quick to
    | specify a specific custom language line for a given attribute rule.
    |
    */

    'custom' => [
        'attribute-name' => [
            'rule-name' => 'custom-message',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Attributes
    |--------------------------------------------------------------------------
    |
    | The following language lines are used to swap our attribute placeholder
    | with something more reader friendly such as "E-Mail Address" instead
    | of "email". This simply helps us make our message more expressive.
    |
    */

    'attributes' => [
        'name'  => '名前',
        'email'  => 'メールアドレス',
        'password'  => 'パスワード',
        'terms' => '規約',
    ],

];


これでWEB画面をリロードすると次のように項目が日本語になっています。

エラーを出してみました。日本語になっています。

Jetstreamで登録してみる

今度はしっかり登録してみます。が、エラー出ました。HasApiTokens が見つからないそうで、実際、モデルのUser.phpのHasApiTokensをマウスオーバーしても何も表示されません。
検索して、stackoverflowというサイトにヒントが。sanctumが入ってないからだそう。ターミナルに次のコードを入力します。

composer require laravel/sanctum

もう一度、登録をしてみます。
今度はちゃんとダッシュボードにたどり着きました。

上部右のTeamをクリックすると以下のリンクが出ます。

  • チーム管理
    ・チーム設定
    ・新規チーム作成
  • チーム切替
    ・名前s Team

その横の名前だけのブロックをクリックすると以下のリンクです。

  • アカウント管理
    ・プロフィール
    ・ログアウト

プロフィールページでできること

ダッシュボードのプロフィールのリンクをクリックしてみます。

プロフィールページでは、次のことができます。

  1. プロフィールの編集
    名前・メールアドレスの更新
  2. パスワードの更新
  3. 二段階認証
    ログインに二段階認証を設定できます。
  4. ブラウザセッション
    ブラウザから端末のセッションをログアウトさせます。

二段階認証あたりが魅力です。有効化してみましょう。

二段階認証に関して

二段階認証の有効化ボタンを押すとパスワードの入力を求められました。

入力すると、二段階認証が済んで、有効画面がでて、QRコードと、リカバリーコードが表示されます。

このQRコードはスマホで読み込みますので、第一前提で、スマホ(タブレット)が必要となります。
トークンはGoogle Authenticatorアプリから取得してねと書かれているので、スマホにインストールします。
スマホが無い場合は、おそらく、リカバリーコードでログインするのだと思うので試してみます。
ログインでメールアドレスとパスワード入力後、次の画面になりました。

リカバリーコードを使用する リンクをクリックします。
先ほどの二段階認証の設定画面にあった、リカバリーコードを1つ適当に選んで入力します。

ダッシュボードにログインできました。


スマホで確認コードを見る場合は、先ほどのQRコードをもう一度見る必要があります。
しかし、PCで先にテストしたため、リカバリーコードの表示しかできません。

しょうがないので、いったん、無効化して、再度、有効化して、QRコードを表示したいと思います。

QRコードをスキャンし、リカバリーコードも再保存しました。
ログインしてみます。

先ほど同様、メールアドレスとパスワードの入力画面で、両方を入力後、次の画面になります。

ここで、スマホのGoogle Authenticatorアプリに表示されている数字を入力し、有効ならダッシュボードに移行します。


上記はスマホのGoogle Authenticatorアプリの表示です。
2つあるのは、間違って、2回QRコードを読み込んだからです。
下のほうが新しいコード。

コード自体は、30秒でリフレッシュされます。30秒しか有効ではないワンタイムトークンって感じなのでちょっとしたセキュリティ対策には、便利だと思います。

チームの紹介に関しては別記事にしたいと思います。