[{"data":1,"prerenderedAt":3846},["ShallowReactive",2],{"article-laravel-nuxt-jwt-spa":3},{"id":4,"title":5,"body":6,"category":3833,"createdAt":3835,"description":5,"extension":3836,"index":3837,"meta":3838,"navigation":619,"path":3839,"publish":619,"seo":3840,"series":3837,"seriesTitle":3837,"stem":3841,"tag":3842,"thumbnail":3844,"updatedAt":3835,"__hash__":3845},"articles\u002Farticles\u002Flaravel-nuxt-jwt-spa.md","laravel 6 + Nuxt.js で作るJWT認証つきSPA構築",{"type":7,"value":8,"toc":3796},"minimark",[9,13,16,19,22,30,35,38,44,47,63,66,70,82,400,423,445,449,452,461,480,484,487,491,494,501,507,513,517,520,527,534,540,544,555,559,562,568,585,588,591,597,603,682,689,695,698,701,704,710,713,719,725,729,986,990,1000,1135,1138,1144,1148,1155,1200,1203,1209,1212,1219,1225,1230,1635,1638,1642,1651,1655,1658,1665,1668,1671,1678,1682,1685,1688,1693,1699,1703,1729,1733,1739,1757,1842,1856,1860,1869,1872,1875,1881,1885,1891,1897,1900,1906,2219,2222,2233,2240,2261,2268,2271,2274,2389,2402,2408,2420,2423,2426,2429,2432,2439,3633,3644,3650,3653,3656,3659,3662,3665,3668,3671,3674,3701,3705,3708,3714,3723,3726,3729,3733,3736,3764,3767,3770,3792],[10,11,12],"p",{},"こんにちはjunです。laravel をAPIサーバーとして扱いフロントはNuxt.jsのSPAで構築するプロジェクトがありました。認証を実装したり初期のセッティングでそこそこ詰まったのでメモがてら記事にします。",[10,14,15],{},"この手の記事にありがちな「開発サーバーまでの段階しかやらない」ではなくSPAをビルドしてDocker上の仮想的に作成したサーバー環境で実際に一つのアプリケーションとして動かすとこまでやってみます。",[10,17,18],{},"独立したフロントエンド とバックをどうやってつなげて、どんなサーバー構成にすればいいのか？という視点で見ていただければ幸いです。また私も昨日にようやく自分の頭で纏った程度なので、この手のアプリケーション作成がﾁｮｯﾄﾃﾞｷﾙ人はぜひアドバイスやコメントお願いします。",[10,20,21],{},"Dockerを用いた環境構築概要から話しています。環境がありLravelとNuxtのAPI連携について知りたい人は **「Larvel にJWT認証機能を追加する」**から読みはじめてください。",[10,23,24,25,29],{},"使用環境\ndocker：19.03.13\nmaxOS Catalina：10.15.5\ncomposer：1.10.6\nNode.js：12.19.0\n",[26,27,28],"strong",{},"Laravel：6.20","\nNuxt.js：2.14.6",[31,32,34],"h2",{"id":33},"dockerで仮想環境を構築","Dockerで仮想環境を構築",[10,36,37],{},"私が今回構築するサーバー構成は以下の図の感じです。",[39,40],"image-render",{":src":41,":width":42,":center":43},"'_mix\u002Flaravel-nuxt.jpeg'","'500px'","true",[10,45,46],{},"webサーバーではバーチャルホスト を使って、80・443などの通常のHTTP通信に対してはNuxt.jsのビルドファイルを返します。そして8000ポートにはLaravelのプロジェクトをおいて、APIサーバーとして使用します。",[10,48,49,50,54,55,58,59,62],{},"Nuxt.jsはLaravelから発行されたトークンを用いてAPIにアクセスしてデータを引っ張ります。実際の運用ではドメインが付与されるので、例えば",[51,52,53],"code",{},"service.com","として、",[51,56,57],{},"http(s):\u002F\u002Fservice.com","はNuxt.jsへ、そしてNuxt.jsは",[51,60,61],{},"https:\u002F\u002Fapi.service.com","へAPIを飛ばします。",[10,64,65],{},"バーチャルホスト の設定をすることで公開側とAPIをconfレベルで分けることができます。つまりDockerのwebサーバーイメージには、ApacheまたはNginxの設定ファイルをボリュームして、それぞれのドキュメントルート を指定できるような環境があれば大丈夫です。（無理に私のイメージとかに合わせなくても大丈夫ということです。）",[67,68,69],"h3",{"id":69},"docker-composeは以下のような感じ",[10,71,72,77,78,81],{},[73,74,76],"a",{"href":75},"\u002Farticles\u002Fbuild-lamp-with-docker","こちら","記事で作成したイメージを使用します。cenotsから構築したLAMP環境です。",[51,79,80],{},"centos_apache","イメージを用いてweb側をビルドしています。",[83,84,90],"pre",{"className":85,"code":86,"filename":87,"language":88,"meta":89,"style":89},"language-yml shiki shiki-themes material-theme-ocean","version: '3'\nservices: \n  web_1:\n    image: centos_apache:1.0\n    depends_on: \n      - db\n    volumes: \n      - .\u002Fhtml\u002F:\u002Fvar\u002Fwww\u002Fhtml\u002F\n      - .\u002Fweb_1\u002Fhttpd.conf:\u002Fetc\u002Fhttpd\u002Fconf\u002Fhttpd.conf\n      - \u002Fsys\u002Ffs\u002Fcgroup:\u002Fsys\u002Ffs\u002Fcgroup:ro\n    ports: \n      - \"9000:80\"\n      - \"3000:3000\"\n      - \"8000:8000\"\n    privileged: true\n    command: \u002Fsbin\u002Finit\n  db:\n    image: mysql:5.7\n    environment:\n      MYSQL_DATABASE: trend_system\n      MYSQL_USER: trend\n      MYSQL_PASSWORD: trendtrend\n      MYSQL_ROOT_PASSWORD: rootroot\n    ports: \n      - \"3306:3306\"\n    volumes: \n      - laravel_data:\u002Fvar\u002Flib\u002Fmysql\nvolumes: \n  laravel_data: {}\n","docker-compose.yml","yml","",[51,91,92,115,127,136,147,157,166,176,184,192,200,210,224,236,248,260,271,279,289,297,308,319,330,341,350,362,371,379,389],{"__ignoreMap":89},[93,94,97,101,105,108,112],"span",{"class":95,"line":96},"line",1,[93,98,100],{"class":99},"s-wAU","version",[93,102,104],{"class":103},"sAklC",":",[93,106,107],{"class":103}," '",[93,109,111],{"class":110},"sfyAc","3",[93,113,114],{"class":103},"'\n",[93,116,118,121,123],{"class":95,"line":117},2,[93,119,120],{"class":99},"services",[93,122,104],{"class":103},[93,124,126],{"class":125},"s0W1g"," \n",[93,128,130,133],{"class":95,"line":129},3,[93,131,132],{"class":99},"  web_1",[93,134,135],{"class":103},":\n",[93,137,139,142,144],{"class":95,"line":138},4,[93,140,141],{"class":99},"    image",[93,143,104],{"class":103},[93,145,146],{"class":110}," centos_apache:1.0\n",[93,148,150,153,155],{"class":95,"line":149},5,[93,151,152],{"class":99},"    depends_on",[93,154,104],{"class":103},[93,156,126],{"class":125},[93,158,160,163],{"class":95,"line":159},6,[93,161,162],{"class":103},"      -",[93,164,165],{"class":110}," db\n",[93,167,169,172,174],{"class":95,"line":168},7,[93,170,171],{"class":99},"    volumes",[93,173,104],{"class":103},[93,175,126],{"class":125},[93,177,179,181],{"class":95,"line":178},8,[93,180,162],{"class":103},[93,182,183],{"class":110}," .\u002Fhtml\u002F:\u002Fvar\u002Fwww\u002Fhtml\u002F\n",[93,185,187,189],{"class":95,"line":186},9,[93,188,162],{"class":103},[93,190,191],{"class":110}," .\u002Fweb_1\u002Fhttpd.conf:\u002Fetc\u002Fhttpd\u002Fconf\u002Fhttpd.conf\n",[93,193,195,197],{"class":95,"line":194},10,[93,196,162],{"class":103},[93,198,199],{"class":110}," \u002Fsys\u002Ffs\u002Fcgroup:\u002Fsys\u002Ffs\u002Fcgroup:ro\n",[93,201,203,206,208],{"class":95,"line":202},11,[93,204,205],{"class":99},"    ports",[93,207,104],{"class":103},[93,209,126],{"class":125},[93,211,213,215,218,221],{"class":95,"line":212},12,[93,214,162],{"class":103},[93,216,217],{"class":103}," \"",[93,219,220],{"class":110},"9000:80",[93,222,223],{"class":103},"\"\n",[93,225,227,229,231,234],{"class":95,"line":226},13,[93,228,162],{"class":103},[93,230,217],{"class":103},[93,232,233],{"class":110},"3000:3000",[93,235,223],{"class":103},[93,237,239,241,243,246],{"class":95,"line":238},14,[93,240,162],{"class":103},[93,242,217],{"class":103},[93,244,245],{"class":110},"8000:8000",[93,247,223],{"class":103},[93,249,251,254,256],{"class":95,"line":250},15,[93,252,253],{"class":99},"    privileged",[93,255,104],{"class":103},[93,257,259],{"class":258},"sbqyR"," true\n",[93,261,263,266,268],{"class":95,"line":262},16,[93,264,265],{"class":99},"    command",[93,267,104],{"class":103},[93,269,270],{"class":110}," \u002Fsbin\u002Finit\n",[93,272,274,277],{"class":95,"line":273},17,[93,275,276],{"class":99},"  db",[93,278,135],{"class":103},[93,280,282,284,286],{"class":95,"line":281},18,[93,283,141],{"class":99},[93,285,104],{"class":103},[93,287,288],{"class":110}," mysql:5.7\n",[93,290,292,295],{"class":95,"line":291},19,[93,293,294],{"class":99},"    environment",[93,296,135],{"class":103},[93,298,300,303,305],{"class":95,"line":299},20,[93,301,302],{"class":99},"      MYSQL_DATABASE",[93,304,104],{"class":103},[93,306,307],{"class":110}," trend_system\n",[93,309,311,314,316],{"class":95,"line":310},21,[93,312,313],{"class":99},"      MYSQL_USER",[93,315,104],{"class":103},[93,317,318],{"class":110}," trend\n",[93,320,322,325,327],{"class":95,"line":321},22,[93,323,324],{"class":99},"      MYSQL_PASSWORD",[93,326,104],{"class":103},[93,328,329],{"class":110}," trendtrend\n",[93,331,333,336,338],{"class":95,"line":332},23,[93,334,335],{"class":99},"      MYSQL_ROOT_PASSWORD",[93,337,104],{"class":103},[93,339,340],{"class":110}," rootroot\n",[93,342,344,346,348],{"class":95,"line":343},24,[93,345,205],{"class":99},[93,347,104],{"class":103},[93,349,126],{"class":125},[93,351,353,355,357,360],{"class":95,"line":352},25,[93,354,162],{"class":103},[93,356,217],{"class":103},[93,358,359],{"class":110},"3306:3306",[93,361,223],{"class":103},[93,363,365,367,369],{"class":95,"line":364},26,[93,366,171],{"class":99},[93,368,104],{"class":103},[93,370,126],{"class":125},[93,372,374,376],{"class":95,"line":373},27,[93,375,162],{"class":103},[93,377,378],{"class":110}," laravel_data:\u002Fvar\u002Flib\u002Fmysql\n",[93,380,382,385,387],{"class":95,"line":381},28,[93,383,384],{"class":99},"volumes",[93,386,104],{"class":103},[93,388,126],{"class":125},[93,390,392,395,397],{"class":95,"line":391},29,[93,393,394],{"class":99},"  laravel_data",[93,396,104],{"class":103},[93,398,399],{"class":103}," {}\n",[10,401,402,403,406,407,410,411,414,415,418,419,422],{},"ホストマシンの",[51,404,405],{},"localhost:9000","にアクセスするとコンテナの",[51,408,409],{},"localhost:80","につながります。Nuxt.jsの開発サーバーポートとなる",[51,412,413],{},"3000","はホストとコンテナ一緒にしています。多分使わないのですが ",[51,416,417],{},"php artisan serve","で立てるLaravel開発サーバーポート",[51,420,421],{},"8000","も一応用意しておきます。",[10,424,425,426,429,430,433,434,437,438,440,441,444],{},"ホスト側には",[51,427,428],{},"html","ディレクトリに",[51,431,432],{},"frontend","、",[51,435,436],{},"laravel","と言ったディレクトリがあります。Nuxt、Laravelのソースがそれぞれに配置されています。コンテナ起動時にはその",[51,439,428],{},"ディレクトリはコンテナの",[51,442,443],{},"\u002Fvar\u002Fwww\u002Fhtml","にボリュームされます。",[67,446,448],{"id":447},"httpdconfは以下の感じ","httpd.confは以下の感じ",[10,450,451],{},"Nginx兄貴達にはすみませんが、とりあえず以下のようなバーチャルホスト 設定が立てられば大丈夫です。",[83,453,459],{"className":454,"code":456,"filename":457,"language":458,"meta":89},[455],"language-text","Listen 8000\n\u003CDirectory \"\u002Fvar\u002Fwww\u002Fhtml\u002Ffrontend\u002Fdist\">\n    Options Indexes FollowSymLinks\n    AllowOverride All\n    Require all granted\n\u003C\u002FDirectory>\n\n\u003CVirtualHost *:80>\n    ServerName example.com\n    DocumentRoot \u002Fvar\u002Fwww\u002Fhtml\u002Ffrontend\u002Fdist\n\u003C\u002FVirtualHost>\n\n\u003CVirtualHost *:8000>\n    ServerName example.com\n    DocumentRoot \u002Fvar\u002Fwww\u002Fhtml\u002Flaravel\u002Fpublic\n\u003C\u002FVirtualHost>\n","httpd.conf","text",[51,460,456],{"__ignoreMap":89},[10,462,463,464,467,468,471,472,475,476,479],{},"forntendはnuxtのプロジェクトディレクトリ、laravelはLaravelのプロジェクトディレクトリ名です。80でリクエストが来たらnuxtのビルドした",[51,465,466],{},"index.html","がある",[51,469,470],{},"\u002Fvar\u002Fwww\u002Fhtml\u002Ffrontend\u002Fdist","へ飛ばされます。一応後でブラウザからはアクセスできないようにしますが、8000できたリクエストは",[51,473,474],{},"\u002Fvar\u002Fwww\u002Fhtml\u002Flaravel\u002Fpublic","の",[51,477,478],{},"index.php","がキャッチします。",[67,481,483],{"id":482},"ぶっちゃけdockerなくてもとりあえず行けます","ぶっちゃけDockerなくてもとりあえず行けます",[10,485,486],{},"初心者の人は「？」となるかもしれません。しかしDBがあり、ホストマシン上でnuxtプロジェクトとLaravelお互いの開発サーバ同士で連絡が取れれば、見出しの内容は実装可能です。ビルドまでしたり総合的に確かめたい場合にDockerを使用してください。",[31,488,490],{"id":489},"laravelの設定をする","Laravelの設定をする",[67,492,493],{"id":493},"コンテナを起動",[10,495,496,497,500],{},"docker-compose.ymlがあるディレクトリで",[51,498,499],{},"docker-compose up -d"," をします。特に問題なければコンテナーが起動するはずです。起動したら",[83,502,505],{"className":503,"code":504,"language":458},[455],"docker exec -it {web側のコンテナ名} \u002Fbin\u002Fbash\n",[51,506,504],{"__ignoreMap":89},[10,508,509,510,512],{},"をしてコンテナに入りましょう。",[51,511,443],{},"にいくとマウントしたLaravelプロジェクトとNuxt.jsプロジェクトがいるはずです。",[67,514,516],{"id":515},"laravel-のenvファイルを変更","laravel のenvファイルを変更",[10,518,519],{},"マイグレーションをしたいのでlaravelのenvを設定します。",[83,521,525],{"className":522,"code":523,"filename":524,"language":458,"meta":89},[455],"DB_CONNECTION=mysql\nDB_HOST=db \u002F\u002F docker-compose.yml で定義したDBのコンテナ\nDB_PORT=3306\nDB_DATABASE=laravel_test\nDB_USERNAME=root\nDB_PASSWORD=rootroot\n",".env",[51,526,523],{"__ignoreMap":89},[10,528,529,530,533],{},"docker-composeのおかげでこの設定であればつながります。コンテナの中",[51,531,532],{},"\u002Fvar\u002Fwww\u002Fhtmm\u002Flaravel","にてマイグレーションを実行します。",[83,535,538],{"className":536,"code":537,"language":458},[455],"$ php artisan migrate\n",[51,539,537],{"__ignoreMap":89},[31,541,543],{"id":542},"larvel-にjwt認証機能を追加する","Larvel にJWT認証機能を追加する",[10,545,546,547,550,551,554],{},"ここからが本番です。ちなみに私が使用している",[26,548,549],{},"Laravel はバージョン6.2.0","です。バージョンによって設定が異なったりします。この ",[26,552,553],{},"記事は2020年12月時点でLravel 8 は出ているけど、LTSなどの都合でLravel 6を使用するという状況で書いています。"," sライブラリなどはあえてバージョンを指定したりしていますので注意してください。",[67,556,558],{"id":557},"jwtライブラリをインストール","JWTライブラリをインストール",[10,560,561],{},"Laravelには標準でJTWが入っていないのでライブラリをインストールします。",[83,563,566],{"className":564,"code":565,"language":458},[455],"composer require tymon\u002Fjwt-auth:1.0.0-rc.5\n",[51,567,565],{"__ignoreMap":89},[10,569,570,573,574,577,578,584],{},[51,571,572],{},"tymon\u002Fjwt-auth"," というライブラリを入れますが、Laravel 6 の場合はバージョンに",[51,575,576],{},":1.0.0-rc.5","を指定しないとエラーになります。以下は",[73,579,583],{"href":580,"rel":581},"https:\u002F\u002Fjwt-auth.readthedocs.io\u002Fen\u002Fdevelop\u002F",[582],"nofollow","このライブラリのドキュメント","通りの実装です。",[67,586,587],{"id":587},"設定を一部変更",[10,589,590],{},"ライブラリのインストールをすればJWTは使えるようになります。しかし今回の構築では一部変更しなければならない箇所があったので、設定ファイルを生成します。",[83,592,595],{"className":593,"code":594,"language":458},[455],"php artisan vendor:publish --provider=\"Tymon\\JWTAuth\\Providers\\LaravelServiceProvider\"\n",[51,596,594],{"__ignoreMap":89},[10,598,599,602],{},[51,600,601],{},"config\u002Fjwt.php","というファイルが生成されたはずです。このファイルにおいて以下の部分を書き換えます。",[83,604,608],{"className":605,"code":606,"language":607,"meta":89,"style":89},"language-php shiki shiki-themes material-theme-ocean","'providers' => [\n\n\u002F*\n|--------------------------------------------------------------------------\n| JWT Provider\n|--------------------------------------------------------------------------\n|\n| Specify the provider that is used to create and decode the tokens.\n|\n*\u002F\n\n\u002F\u002F 'jwt' => Tymon\\JWTAuth\\Providers\\JWT\\Lcobucci::class,\n'jwt' => Tymon\\JWTAuth\\Providers\\JWT\\Namshi::class,\n\n]\n","php",[51,609,610,615,621,626,631,636,640,645,650,654,659,663,668,673,677],{"__ignoreMap":89},[93,611,612],{"class":95,"line":96},[93,613,614],{},"'providers' => [\n",[93,616,617],{"class":95,"line":117},[93,618,620],{"emptyLinePlaceholder":619},true,"\n",[93,622,623],{"class":95,"line":129},[93,624,625],{},"\u002F*\n",[93,627,628],{"class":95,"line":138},[93,629,630],{},"|--------------------------------------------------------------------------\n",[93,632,633],{"class":95,"line":149},[93,634,635],{},"| JWT Provider\n",[93,637,638],{"class":95,"line":159},[93,639,630],{},[93,641,642],{"class":95,"line":168},[93,643,644],{},"|\n",[93,646,647],{"class":95,"line":178},[93,648,649],{},"| Specify the provider that is used to create and decode the tokens.\n",[93,651,652],{"class":95,"line":186},[93,653,644],{},[93,655,656],{"class":95,"line":194},[93,657,658],{},"*\u002F\n",[93,660,661],{"class":95,"line":202},[93,662,620],{"emptyLinePlaceholder":619},[93,664,665],{"class":95,"line":212},[93,666,667],{},"\u002F\u002F 'jwt' => Tymon\\JWTAuth\\Providers\\JWT\\Lcobucci::class,\n",[93,669,670],{"class":95,"line":226},[93,671,672],{},"'jwt' => Tymon\\JWTAuth\\Providers\\JWT\\Namshi::class,\n",[93,674,675],{"class":95,"line":238},[93,676,620],{"emptyLinePlaceholder":619},[93,678,679],{"class":95,"line":250},[93,680,681],{},"]\n",[10,683,684,685,688],{},"JWTのプロバイダーを",[51,686,687],{},"Tymon\\JWTAuth\\Providers\\JWT\\Namshi::class","に変更します。というのも標準の設定でいくと",[83,690,693],{"className":691,"code":692,"language":458},[455],"Tymon\\JWTAuth\\Exceptions\\JWTException: Could not create token: Implicit conversion of keys from strings is deprecated. Please use InMemory or LocalFileReference classes. \n",[51,694,692],{"__ignoreMap":89},[10,696,697],{},"というエラーが生じます。JWTトークンを生成する処理に非推奨な部分があるそうで、プロバイダを変更する必要がありました。参考記事にあるgithub issueがお世話になりました。",[67,699,700],{"id":700},"シークレットを生成",[10,702,703],{},"JWTトークンを生成するためのシークレットを作成します。",[83,705,708],{"className":706,"code":707,"language":458},[455],"php artisan jwt:secret\n",[51,709,707],{"__ignoreMap":89},[10,711,712],{},"するとenvファイルの下の方に",[83,714,717],{"className":715,"code":716,"language":458},[455],"JWT_SECRET=ve1b******\n",[51,718,716],{"__ignoreMap":89},[10,720,721,722,724],{},"というものが生成されます。ちなみにこのシークレットは絶対に外部に漏れてはいけません。間違ってgithubとかに上げないように ",[51,723,524],{},"ファイルはgitignoreしましょう。",[67,726,728],{"id":727},"userモデルにメソッドを追加","Userモデルにメソッドを追加",[83,730,733],{"className":605,"code":731,"filename":732,"language":607,"meta":89,"style":89},"\u003C?php\n\nnamespace App;\n\nuse Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Tymon\\JWTAuth\\Contracts\\JWTSubject; \u002F\u002F追加\n\nclass User extends Authenticatable implements JWTSubject \u002F\u002F追加\n{\n    use Notifiable;\n\n    \u002F**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     *\u002F\n    protected $fillable = [\n        'name', 'email', 'password',\n    ];\n\n    \u002F**\n     * The attributes that should be hidden for arrays.\n     *\n     * @var array\n     *\u002F\n    protected $hidden = [\n        'password', 'remember_token',\n    ];\n\n    \u002F**\n     * The attributes that should be cast to native types.\n     *\n     * @var array\n     *\u002F\n    protected $casts = [\n        'email_verified_at' => 'datetime',\n    ];\n\n    public function getJWTIdentifier()　 \u002F\u002F追加\n    {\n        return $this->getKey();\n    }\n\n    public function getJWTCustomClaims()　 \u002F\u002F追加\n    {\n        return [];\n    }\n}\n","app\u002FUser.php",[51,734,735,740,744,749,753,758,763,768,773,777,782,787,792,796,801,806,811,816,821,826,831,836,840,844,849,853,857,861,866,871,876,881,886,892,897,902,907,913,919,924,929,935,941,947,953,958,964,969,975,980],{"__ignoreMap":89},[93,736,737],{"class":95,"line":96},[93,738,739],{},"\u003C?php\n",[93,741,742],{"class":95,"line":117},[93,743,620],{"emptyLinePlaceholder":619},[93,745,746],{"class":95,"line":129},[93,747,748],{},"namespace App;\n",[93,750,751],{"class":95,"line":138},[93,752,620],{"emptyLinePlaceholder":619},[93,754,755],{"class":95,"line":149},[93,756,757],{},"use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\n",[93,759,760],{"class":95,"line":159},[93,761,762],{},"use Illuminate\\Foundation\\Auth\\User as Authenticatable;\n",[93,764,765],{"class":95,"line":168},[93,766,767],{},"use Illuminate\\Notifications\\Notifiable;\n",[93,769,770],{"class":95,"line":178},[93,771,772],{},"use Tymon\\JWTAuth\\Contracts\\JWTSubject; \u002F\u002F追加\n",[93,774,775],{"class":95,"line":186},[93,776,620],{"emptyLinePlaceholder":619},[93,778,779],{"class":95,"line":194},[93,780,781],{},"class User extends Authenticatable implements JWTSubject \u002F\u002F追加\n",[93,783,784],{"class":95,"line":202},[93,785,786],{},"{\n",[93,788,789],{"class":95,"line":212},[93,790,791],{},"    use Notifiable;\n",[93,793,794],{"class":95,"line":226},[93,795,620],{"emptyLinePlaceholder":619},[93,797,798],{"class":95,"line":238},[93,799,800],{},"    \u002F**\n",[93,802,803],{"class":95,"line":250},[93,804,805],{},"     * The attributes that are mass assignable.\n",[93,807,808],{"class":95,"line":262},[93,809,810],{},"     *\n",[93,812,813],{"class":95,"line":273},[93,814,815],{},"     * @var array\n",[93,817,818],{"class":95,"line":281},[93,819,820],{},"     *\u002F\n",[93,822,823],{"class":95,"line":291},[93,824,825],{},"    protected $fillable = [\n",[93,827,828],{"class":95,"line":299},[93,829,830],{},"        'name', 'email', 'password',\n",[93,832,833],{"class":95,"line":310},[93,834,835],{},"    ];\n",[93,837,838],{"class":95,"line":321},[93,839,620],{"emptyLinePlaceholder":619},[93,841,842],{"class":95,"line":332},[93,843,800],{},[93,845,846],{"class":95,"line":343},[93,847,848],{},"     * The attributes that should be hidden for arrays.\n",[93,850,851],{"class":95,"line":352},[93,852,810],{},[93,854,855],{"class":95,"line":364},[93,856,815],{},[93,858,859],{"class":95,"line":373},[93,860,820],{},[93,862,863],{"class":95,"line":381},[93,864,865],{},"    protected $hidden = [\n",[93,867,868],{"class":95,"line":391},[93,869,870],{},"        'password', 'remember_token',\n",[93,872,874],{"class":95,"line":873},30,[93,875,835],{},[93,877,879],{"class":95,"line":878},31,[93,880,620],{"emptyLinePlaceholder":619},[93,882,884],{"class":95,"line":883},32,[93,885,800],{},[93,887,889],{"class":95,"line":888},33,[93,890,891],{},"     * The attributes that should be cast to native types.\n",[93,893,895],{"class":95,"line":894},34,[93,896,810],{},[93,898,900],{"class":95,"line":899},35,[93,901,815],{},[93,903,905],{"class":95,"line":904},36,[93,906,820],{},[93,908,910],{"class":95,"line":909},37,[93,911,912],{},"    protected $casts = [\n",[93,914,916],{"class":95,"line":915},38,[93,917,918],{},"        'email_verified_at' => 'datetime',\n",[93,920,922],{"class":95,"line":921},39,[93,923,835],{},[93,925,927],{"class":95,"line":926},40,[93,928,620],{"emptyLinePlaceholder":619},[93,930,932],{"class":95,"line":931},41,[93,933,934],{},"    public function getJWTIdentifier()　 \u002F\u002F追加\n",[93,936,938],{"class":95,"line":937},42,[93,939,940],{},"    {\n",[93,942,944],{"class":95,"line":943},43,[93,945,946],{},"        return $this->getKey();\n",[93,948,950],{"class":95,"line":949},44,[93,951,952],{},"    }\n",[93,954,956],{"class":95,"line":955},45,[93,957,620],{"emptyLinePlaceholder":619},[93,959,961],{"class":95,"line":960},46,[93,962,963],{},"    public function getJWTCustomClaims()　 \u002F\u002F追加\n",[93,965,967],{"class":95,"line":966},47,[93,968,940],{},[93,970,972],{"class":95,"line":971},48,[93,973,974],{},"        return [];\n",[93,976,978],{"class":95,"line":977},49,[93,979,952],{},[93,981,983],{"class":95,"line":982},50,[93,984,985],{},"}\n",[67,987,989],{"id":988},"authphpの認証ドライバを変更","auth.phpの認証ドライバを変更",[10,991,992,995,996,999],{},[51,993,994],{},"config\u002Fauth.php","にて",[51,997,998],{},"Authentication","認証ドライバを変更します。",[83,1001,1003],{"className":605,"code":1002,"filename":994,"language":607,"meta":89,"style":89},"    \u002F*\n    |--------------------------------------------------------------------------\n    | Authentication Defaults\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default authentication \"guard\" and password\n    | reset options for your application. You may change these defaults\n    | as required, but they're a perfect start for most applications.\n    |\n    *\u002F\n\n    'defaults' => [\n        'guard' => 'api', \u002F\u002F変更\n        'passwords' => 'users',\n    ],\n...\n    'guards' => [\n        'web' => [\n            'driver' => 'session',\n            'provider' => 'users',\n        ],\n\n        'api' => [\n            'driver' => 'jwt', \u002F\u002F変更\n            'provider' => 'users',\n            'hash' => false,\n",[51,1004,1005,1010,1015,1020,1024,1029,1034,1039,1044,1048,1053,1057,1062,1070,1075,1080,1085,1090,1095,1100,1105,1110,1114,1119,1126,1130],{"__ignoreMap":89},[93,1006,1007],{"class":95,"line":96},[93,1008,1009],{},"    \u002F*\n",[93,1011,1012],{"class":95,"line":117},[93,1013,1014],{},"    |--------------------------------------------------------------------------\n",[93,1016,1017],{"class":95,"line":129},[93,1018,1019],{},"    | Authentication Defaults\n",[93,1021,1022],{"class":95,"line":138},[93,1023,1014],{},[93,1025,1026],{"class":95,"line":149},[93,1027,1028],{},"    |\n",[93,1030,1031],{"class":95,"line":159},[93,1032,1033],{},"    | This option controls the default authentication \"guard\" and password\n",[93,1035,1036],{"class":95,"line":168},[93,1037,1038],{},"    | reset options for your application. You may change these defaults\n",[93,1040,1041],{"class":95,"line":178},[93,1042,1043],{},"    | as required, but they're a perfect start for most applications.\n",[93,1045,1046],{"class":95,"line":186},[93,1047,1028],{},[93,1049,1050],{"class":95,"line":194},[93,1051,1052],{},"    *\u002F\n",[93,1054,1055],{"class":95,"line":202},[93,1056,620],{"emptyLinePlaceholder":619},[93,1058,1059],{"class":95,"line":212},[93,1060,1061],{},"    'defaults' => [\n",[93,1063,1064,1067],{"class":95,"line":226},[93,1065,1066],{},"        'guard' => 'api',",[93,1068,1069],{}," \u002F\u002F変更\n",[93,1071,1072],{"class":95,"line":238},[93,1073,1074],{},"        'passwords' => 'users',\n",[93,1076,1077],{"class":95,"line":250},[93,1078,1079],{},"    ],\n",[93,1081,1082],{"class":95,"line":262},[93,1083,1084],{},"...\n",[93,1086,1087],{"class":95,"line":273},[93,1088,1089],{},"    'guards' => [\n",[93,1091,1092],{"class":95,"line":281},[93,1093,1094],{},"        'web' => [\n",[93,1096,1097],{"class":95,"line":291},[93,1098,1099],{},"            'driver' => 'session',\n",[93,1101,1102],{"class":95,"line":299},[93,1103,1104],{},"            'provider' => 'users',\n",[93,1106,1107],{"class":95,"line":310},[93,1108,1109],{},"        ],\n",[93,1111,1112],{"class":95,"line":321},[93,1113,620],{"emptyLinePlaceholder":619},[93,1115,1116],{"class":95,"line":332},[93,1117,1118],{},"        'api' => [\n",[93,1120,1121,1124],{"class":95,"line":343},[93,1122,1123],{},"            'driver' => 'jwt',",[93,1125,1069],{},[93,1127,1128],{"class":95,"line":352},[93,1129,1104],{},[93,1131,1132],{"class":95,"line":364},[93,1133,1134],{},"            'hash' => false,\n",[10,1136,1137],{},"configはキャッシュされていますので、configをいじった後はキャッシュクリアをしましょう。",[83,1139,1142],{"className":1140,"code":1141,"language":458},[455],"php artisan config:clear\n",[51,1143,1141],{"__ignoreMap":89},[67,1145,1147],{"id":1146},"jwt認証用のルートを作成","JWT認証用のルートを作成",[10,1149,1150,1151,1154],{},"認証のルートを作成します。",[51,1152,1153],{},"route\u002Fapi.php","に以下のように記述します。",[83,1156,1158],{"className":605,"code":1157,"filename":1153,"language":607,"meta":89,"style":89},"Route::prefix('v1')->group(function(){\n    Route::group(['middleware' => 'api', 'prefix' => 'auth'], function ($router) {\n        Route::post('login', 'AuthController@login')->name('login');;\n        Route::post('logout', 'AuthController@logout');\n        Route::post('refresh', 'AuthController@refresh');\n        Route::get('me', 'AuthController@me');\n    });\n});\n",[51,1159,1160,1165,1170,1175,1180,1185,1190,1195],{"__ignoreMap":89},[93,1161,1162],{"class":95,"line":96},[93,1163,1164],{},"Route::prefix('v1')->group(function(){\n",[93,1166,1167],{"class":95,"line":117},[93,1168,1169],{},"    Route::group(['middleware' => 'api', 'prefix' => 'auth'], function ($router) {\n",[93,1171,1172],{"class":95,"line":129},[93,1173,1174],{},"        Route::post('login', 'AuthController@login')->name('login');;\n",[93,1176,1177],{"class":95,"line":138},[93,1178,1179],{},"        Route::post('logout', 'AuthController@logout');\n",[93,1181,1182],{"class":95,"line":149},[93,1183,1184],{},"        Route::post('refresh', 'AuthController@refresh');\n",[93,1186,1187],{"class":95,"line":159},[93,1188,1189],{},"        Route::get('me', 'AuthController@me');\n",[93,1191,1192],{"class":95,"line":168},[93,1193,1194],{},"    });\n",[93,1196,1197],{"class":95,"line":178},[93,1198,1199],{},"});\n",[10,1201,1202],{},"ルートの設定は運用によって変わると思いますが、APIはバージョンで予め分けておくと将来の拡張性が高まります。一回ぽっきりのサービスでも実装して損はないと思います。上記のルートでは以下のような設定になります。",[83,1204,1207],{"className":1205,"code":1206,"language":458},[455],"$ php artisan route:list\n+--------+----------+---------------------+-------+---------------------------------------------+--------------+\n| Domain | Method   | URI                 | Name  | Action                                      | Middleware   |\n+--------+----------+---------------------+-------+---------------------------------------------+--------------+\n|        | POST     | api\u002Fv1\u002Fauth\u002Flogin   | login | App\\Http\\Controllers\\AuthController@login   | api          |\n|        | POST     | api\u002Fv1\u002Fauth\u002Flogout  |       | App\\Http\\Controllers\\AuthController@logout  | api,auth:api |\n|        | GET|HEAD | api\u002Fv1\u002Fauth\u002Fme      |       | App\\Http\\Controllers\\AuthController@me      | api,auth:api |\n|        | POST     | api\u002Fv1\u002Fauth\u002Frefresh |       | App\\Http\\Controllers\\AuthController@refresh | api,auth:api |\n+--------+----------+---------------------+-------+---------------------------------------------+--------------+\n",[51,1208,1206],{"__ignoreMap":89},[67,1210,1211],{"id":1211},"認証ルートに対するコントローラを作成",[10,1213,1214,1215,1218],{},"それぞれのルートは",[51,1216,1217],{},"AuthController.php","につなげる予定ですので、そのコントローラーを作成します。",[83,1220,1223],{"className":1221,"code":1222,"language":458},[455],"php artisan make:controller AuthController\n",[51,1224,1222],{"__ignoreMap":89},[10,1226,1227,1229],{},[51,1228,1217],{},"は以下のような設定になります。",[83,1231,1234],{"className":605,"code":1232,"filename":1233,"language":607,"meta":89,"style":89},"\u003C?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Auth;\n\nclass AuthController extends Controller\n{\n    \u002F**\n     * Create a new AuthController instance.\n     *\n     * @return void\n     *\u002F\n    public function __construct()\n    {\n        $this->middleware('auth:api', ['except' => ['login']]);\n    }\n\n    \u002F**\n     * Get a JWT via given credentials.\n     *\n     * @return \\Illuminate\\Http\\JsonResponse\n     *\u002F\n    public function login()\n    {\n        $credentials = request(['email', 'password']);\n\n        if (! $token = auth()->attempt($credentials)) {\n            return response()->json(['error' => 'Unauthorized'], 401);\n        }\n\n        return $this->respondWithToken($token);\n    }\n\n    \u002F**\n     * Get the authenticated User.\n     *\n     * @return \\Illuminate\\Http\\JsonResponse\n     *\u002F\n    public function me()\n    {\n        return response()->json(auth()->user());\n    }\n\n    \u002F**\n     * Log the user out (Invalidate the token).\n     *\n     * @return \\Illuminate\\Http\\JsonResponse\n     *\u002F\n    public function logout()\n    {\n        auth()->logout();\n\n        return response()->json(['message' => 'Successfully logged out']);\n    }\n\n    \u002F**\n     * Refresh a token.\n     *\n     * @return \\Illuminate\\Http\\JsonResponse\n     *\u002F\n    public function refresh()\n    {\n        return $this->respondWithToken(auth()->refresh());\n    }\n\n    \u002F**\n     * Get the token array structure.\n     *\n     * @param  string $token\n     *\n     * @return \\Illuminate\\Http\\JsonResponse\n     *\u002F\n    protected function respondWithToken($token)\n    {\n        return response()->json([\n            'access_token' => $token,\n            'token_type' => 'bearer',\n            'expires_in' => auth()->factory()->getTTL() * 60\n        ]);\n    }\n}\n","app\u002FHttp\u002FControllers\u002FAuthController.php",[51,1235,1236,1240,1244,1249,1253,1258,1263,1267,1272,1276,1280,1285,1289,1294,1298,1303,1307,1312,1316,1320,1324,1329,1333,1338,1342,1347,1351,1356,1360,1365,1370,1375,1379,1384,1388,1392,1396,1401,1405,1409,1413,1418,1422,1427,1431,1435,1439,1444,1448,1452,1456,1462,1467,1473,1478,1484,1489,1494,1499,1505,1510,1515,1520,1526,1531,1537,1542,1547,1552,1558,1563,1569,1574,1579,1584,1590,1595,1601,1607,1613,1619,1625,1630],{"__ignoreMap":89},[93,1237,1238],{"class":95,"line":96},[93,1239,739],{},[93,1241,1242],{"class":95,"line":117},[93,1243,620],{"emptyLinePlaceholder":619},[93,1245,1246],{"class":95,"line":129},[93,1247,1248],{},"namespace App\\Http\\Controllers;\n",[93,1250,1251],{"class":95,"line":138},[93,1252,620],{"emptyLinePlaceholder":619},[93,1254,1255],{"class":95,"line":149},[93,1256,1257],{},"use Illuminate\\Http\\Request;\n",[93,1259,1260],{"class":95,"line":159},[93,1261,1262],{},"use Illuminate\\Support\\Facades\\Auth;\n",[93,1264,1265],{"class":95,"line":168},[93,1266,620],{"emptyLinePlaceholder":619},[93,1268,1269],{"class":95,"line":178},[93,1270,1271],{},"class AuthController extends Controller\n",[93,1273,1274],{"class":95,"line":186},[93,1275,786],{},[93,1277,1278],{"class":95,"line":194},[93,1279,800],{},[93,1281,1282],{"class":95,"line":202},[93,1283,1284],{},"     * Create a new AuthController instance.\n",[93,1286,1287],{"class":95,"line":212},[93,1288,810],{},[93,1290,1291],{"class":95,"line":226},[93,1292,1293],{},"     * @return void\n",[93,1295,1296],{"class":95,"line":238},[93,1297,820],{},[93,1299,1300],{"class":95,"line":250},[93,1301,1302],{},"    public function __construct()\n",[93,1304,1305],{"class":95,"line":262},[93,1306,940],{},[93,1308,1309],{"class":95,"line":273},[93,1310,1311],{},"        $this->middleware('auth:api', ['except' => ['login']]);\n",[93,1313,1314],{"class":95,"line":281},[93,1315,952],{},[93,1317,1318],{"class":95,"line":291},[93,1319,620],{"emptyLinePlaceholder":619},[93,1321,1322],{"class":95,"line":299},[93,1323,800],{},[93,1325,1326],{"class":95,"line":310},[93,1327,1328],{},"     * Get a JWT via given credentials.\n",[93,1330,1331],{"class":95,"line":321},[93,1332,810],{},[93,1334,1335],{"class":95,"line":332},[93,1336,1337],{},"     * @return \\Illuminate\\Http\\JsonResponse\n",[93,1339,1340],{"class":95,"line":343},[93,1341,820],{},[93,1343,1344],{"class":95,"line":352},[93,1345,1346],{},"    public function login()\n",[93,1348,1349],{"class":95,"line":364},[93,1350,940],{},[93,1352,1353],{"class":95,"line":373},[93,1354,1355],{},"        $credentials = request(['email', 'password']);\n",[93,1357,1358],{"class":95,"line":381},[93,1359,620],{"emptyLinePlaceholder":619},[93,1361,1362],{"class":95,"line":391},[93,1363,1364],{},"        if (! $token = auth()->attempt($credentials)) {\n",[93,1366,1367],{"class":95,"line":873},[93,1368,1369],{},"            return response()->json(['error' => 'Unauthorized'], 401);\n",[93,1371,1372],{"class":95,"line":878},[93,1373,1374],{},"        }\n",[93,1376,1377],{"class":95,"line":883},[93,1378,620],{"emptyLinePlaceholder":619},[93,1380,1381],{"class":95,"line":888},[93,1382,1383],{},"        return $this->respondWithToken($token);\n",[93,1385,1386],{"class":95,"line":894},[93,1387,952],{},[93,1389,1390],{"class":95,"line":899},[93,1391,620],{"emptyLinePlaceholder":619},[93,1393,1394],{"class":95,"line":904},[93,1395,800],{},[93,1397,1398],{"class":95,"line":909},[93,1399,1400],{},"     * Get the authenticated User.\n",[93,1402,1403],{"class":95,"line":915},[93,1404,810],{},[93,1406,1407],{"class":95,"line":921},[93,1408,1337],{},[93,1410,1411],{"class":95,"line":926},[93,1412,820],{},[93,1414,1415],{"class":95,"line":931},[93,1416,1417],{},"    public function me()\n",[93,1419,1420],{"class":95,"line":937},[93,1421,940],{},[93,1423,1424],{"class":95,"line":943},[93,1425,1426],{},"        return response()->json(auth()->user());\n",[93,1428,1429],{"class":95,"line":949},[93,1430,952],{},[93,1432,1433],{"class":95,"line":955},[93,1434,620],{"emptyLinePlaceholder":619},[93,1436,1437],{"class":95,"line":960},[93,1438,800],{},[93,1440,1441],{"class":95,"line":966},[93,1442,1443],{},"     * Log the user out (Invalidate the token).\n",[93,1445,1446],{"class":95,"line":971},[93,1447,810],{},[93,1449,1450],{"class":95,"line":977},[93,1451,1337],{},[93,1453,1454],{"class":95,"line":982},[93,1455,820],{},[93,1457,1459],{"class":95,"line":1458},51,[93,1460,1461],{},"    public function logout()\n",[93,1463,1465],{"class":95,"line":1464},52,[93,1466,940],{},[93,1468,1470],{"class":95,"line":1469},53,[93,1471,1472],{},"        auth()->logout();\n",[93,1474,1476],{"class":95,"line":1475},54,[93,1477,620],{"emptyLinePlaceholder":619},[93,1479,1481],{"class":95,"line":1480},55,[93,1482,1483],{},"        return response()->json(['message' => 'Successfully logged out']);\n",[93,1485,1487],{"class":95,"line":1486},56,[93,1488,952],{},[93,1490,1492],{"class":95,"line":1491},57,[93,1493,620],{"emptyLinePlaceholder":619},[93,1495,1497],{"class":95,"line":1496},58,[93,1498,800],{},[93,1500,1502],{"class":95,"line":1501},59,[93,1503,1504],{},"     * Refresh a token.\n",[93,1506,1508],{"class":95,"line":1507},60,[93,1509,810],{},[93,1511,1513],{"class":95,"line":1512},61,[93,1514,1337],{},[93,1516,1518],{"class":95,"line":1517},62,[93,1519,820],{},[93,1521,1523],{"class":95,"line":1522},63,[93,1524,1525],{},"    public function refresh()\n",[93,1527,1529],{"class":95,"line":1528},64,[93,1530,940],{},[93,1532,1534],{"class":95,"line":1533},65,[93,1535,1536],{},"        return $this->respondWithToken(auth()->refresh());\n",[93,1538,1540],{"class":95,"line":1539},66,[93,1541,952],{},[93,1543,1545],{"class":95,"line":1544},67,[93,1546,620],{"emptyLinePlaceholder":619},[93,1548,1550],{"class":95,"line":1549},68,[93,1551,800],{},[93,1553,1555],{"class":95,"line":1554},69,[93,1556,1557],{},"     * Get the token array structure.\n",[93,1559,1561],{"class":95,"line":1560},70,[93,1562,810],{},[93,1564,1566],{"class":95,"line":1565},71,[93,1567,1568],{},"     * @param  string $token\n",[93,1570,1572],{"class":95,"line":1571},72,[93,1573,810],{},[93,1575,1577],{"class":95,"line":1576},73,[93,1578,1337],{},[93,1580,1582],{"class":95,"line":1581},74,[93,1583,820],{},[93,1585,1587],{"class":95,"line":1586},75,[93,1588,1589],{},"    protected function respondWithToken($token)\n",[93,1591,1593],{"class":95,"line":1592},76,[93,1594,940],{},[93,1596,1598],{"class":95,"line":1597},77,[93,1599,1600],{},"        return response()->json([\n",[93,1602,1604],{"class":95,"line":1603},78,[93,1605,1606],{},"            'access_token' => $token,\n",[93,1608,1610],{"class":95,"line":1609},79,[93,1611,1612],{},"            'token_type' => 'bearer',\n",[93,1614,1616],{"class":95,"line":1615},80,[93,1617,1618],{},"            'expires_in' => auth()->factory()->getTTL() * 60\n",[93,1620,1622],{"class":95,"line":1621},81,[93,1623,1624],{},"        ]);\n",[93,1626,1628],{"class":95,"line":1627},82,[93,1629,952],{},[93,1631,1633],{"class":95,"line":1632},83,[93,1634,985],{},[10,1636,1637],{},"これでJWT認証に必要なLarvel側の設定が終了しました。",[31,1639,1641],{"id":1640},"talend-api-testerでapiをチェック","Talend API TesterでAPIをチェック",[10,1643,1644,1645,1650],{},"きちんとAPIが存在しているかを確かめるために、chrome拡張の",[73,1646,1649],{"href":1647,"rel":1648},"https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Ftalend-api-tester-free-ed\u002Faejoelaoggembcahagimdiliamlcdmfm",[582],"Talend API Tester","を用いてチェックします。予めシーダーで作成した仮ユーザーデータを用いて以下のように入力してみます。",[39,1652],{":src":1653,":width":1654},"'_mix\u002Fsch-2020-12-05-14.17.54-768x353.png'","'100%'",[39,1656],{":src":1657,":width":1654},"'_mix\u002Fsch-2020-12-05-14.20.21-768x318.png'",[10,1659,1660,1661,1664],{},"JSONでアクセストークン が帰ってきました。このアクセストークン をリクエストヘッダに入れてリクエストすることで認証が必要なルートにアクセスできるようになります。試しに ",[51,1662,1663],{},"\u002Fapi\u002Fv1\u002Fauth\u002Fme","という現在のユーザー情報を確かめるルートにアクセスしてみます。",[10,1666,1667],{},"HEADERSにAuthorizationというものを追加し、先ほどのトークンを入れています。トークン値は「bearer トークン」という形です。",[39,1669],{":src":1670,":width":1654},"'_mix\u002Fsch-2020-12-05-14.23.34-768x224.png'",[10,1672,1673,1674,1677],{},"ユーザー情報が返ってきましたね。",[51,1675,1676],{},"Authcontroller@me","で定義した返り値がきちんとえられました。ちなみに認証情報がない場合はHTTP 401を返します。",[31,1679,1681],{"id":1680},"nuxtjsからapiを呼ぶ","Nuxt.jsからAPIを呼ぶ",[67,1683,1684],{"id":1684},"前準備",[10,1686,1687],{},"Nuxt.jsの構築に移る前にCORS対策をします。APIサーバーはブラウザからのアクセスを禁止して、XMLHttpRequest（XHR）のみのリクエストを許可するようにします。そしてXHRにはCORSという制約があります。これがあるとローカル以外からのXHRを用いたAPIアクセスが制限されます。特にNuxtを3000ポートで開発している時でもAPIサーバーと通信できるように準備しておきます。",[1689,1690,1692],"h4",{"id":1691},"cors設定のライブラリをインストール","CORS設定のライブラリをインストール",[83,1694,1697],{"className":1695,"code":1696,"language":458},[455],"composer require fruitcake\u002Flaravel-cors\n",[51,1698,1696],{"__ignoreMap":89},[1689,1700,1702],{"id":1701},"apphttpkernelphpのミドルウェア-に追加","app\u002FHttp\u002FKernel.phpのミドルウェア に追加",[83,1704,1707],{"className":605,"code":1705,"filename":1706,"language":607,"meta":89,"style":89},"protected $middleware = [\n    \u002F\u002F ...\n    \\Fruitcake\\Cors\\HandleCors::class,\n];\n","app\u002FHttp\u002FKernel.php",[51,1708,1709,1714,1719,1724],{"__ignoreMap":89},[93,1710,1711],{"class":95,"line":96},[93,1712,1713],{},"protected $middleware = [\n",[93,1715,1716],{"class":95,"line":117},[93,1717,1718],{},"    \u002F\u002F ...\n",[93,1720,1721],{"class":95,"line":129},[93,1722,1723],{},"    \\Fruitcake\\Cors\\HandleCors::class,\n",[93,1725,1726],{"class":95,"line":138},[93,1727,1728],{},"];\n",[1689,1730,1732],{"id":1731},"cors設定ファイルを出力して一部変更","CORS設定ファイルを出力して一部変更",[83,1734,1737],{"className":1735,"code":1736,"language":458},[455],"php artisan vendor:publish --tag=\"cors\"\n",[51,1738,1736],{"__ignoreMap":89},[10,1740,1741,1742,1745,1746,1749,1750,1753,1754,1756],{},"先ほどの",[51,1743,1744],{},"jwt.php","のように",[51,1747,1748],{},"cors.php","が",[51,1751,1752],{},"config\u002F","配下に出現します。その",[51,1755,1748],{},"を以下のように変更します。",[83,1758,1761],{"className":605,"code":1759,"filename":1760,"language":607,"meta":89,"style":89},"...\n    \u002F*\n     * You can enable CORS for 1 or multiple paths.\n     * Example: ['api\u002F*']\n     *\u002F\n    'paths' => ['api\u002F*'],\n...\n    \u002F*\n     * Matches the request origin. `['*']` allows all origins. Wildcards can be used, eg `*.mydomain.com`\n     *\u002F\n    'allowed_origins' => [\n          'http:\u002F\u002Flocalhost',\n          'http:\u002F\u002Flocalhost:3000',\u002F\u002F nuxt\n          'http:\u002F\u002Flocalhost:9000' \u002F\u002F dockerの9000->80\n        ],\n\n...\n","confog\u002Fcors.php",[51,1762,1763,1767,1771,1776,1781,1785,1790,1794,1798,1803,1807,1812,1817,1822,1830,1834,1838],{"__ignoreMap":89},[93,1764,1765],{"class":95,"line":96},[93,1766,1084],{},[93,1768,1769],{"class":95,"line":117},[93,1770,1009],{},[93,1772,1773],{"class":95,"line":129},[93,1774,1775],{},"     * You can enable CORS for 1 or multiple paths.\n",[93,1777,1778],{"class":95,"line":138},[93,1779,1780],{},"     * Example: ['api\u002F*']\n",[93,1782,1783],{"class":95,"line":149},[93,1784,820],{},[93,1786,1787],{"class":95,"line":159},[93,1788,1789],{},"    'paths' => ['api\u002F*'],\n",[93,1791,1792],{"class":95,"line":168},[93,1793,1084],{},[93,1795,1796],{"class":95,"line":178},[93,1797,1009],{},[93,1799,1800],{"class":95,"line":186},[93,1801,1802],{},"     * Matches the request origin. `['*']` allows all origins. Wildcards can be used, eg `*.mydomain.com`\n",[93,1804,1805],{"class":95,"line":194},[93,1806,820],{},[93,1808,1809],{"class":95,"line":202},[93,1810,1811],{},"    'allowed_origins' => [\n",[93,1813,1814],{"class":95,"line":212},[93,1815,1816],{},"          'http:\u002F\u002Flocalhost',\n",[93,1818,1819],{"class":95,"line":226},[93,1820,1821],{},"          'http:\u002F\u002Flocalhost:3000',\u002F\u002F nuxt\n",[93,1823,1824,1827],{"class":95,"line":238},[93,1825,1826],{},"          'http:\u002F\u002Flocalhost:9000'",[93,1828,1829],{}," \u002F\u002F dockerの9000->80\n",[93,1831,1832],{"class":95,"line":250},[93,1833,1109],{},[93,1835,1836],{"class":95,"line":262},[93,1837,620],{"emptyLinePlaceholder":619},[93,1839,1840],{"class":95,"line":273},[93,1841,1084],{},[10,1843,1844,1847,1848,1851,1852,1855],{},[51,1845,1846],{},"api\u002F"," ルート配下に対してcors設定を行い、そして",[51,1849,1850],{},"localhost","及び",[51,1853,1854],{},"3000ポート","からの接続を許可しました。",[67,1857,1859],{"id":1858},"nuxt-auth-モジュールを用いて認証系の機能を整える","nuxt auth モジュールを用いて認証系の機能を整える",[10,1861,1862,1863,1868],{},"nuxt.jsの構築は飛ばします。私の環境では nuxt+bootstrap+axiosで始めます。認証系をpluginで構築してもいいのですが、なかなか大変ですのでnuxt authモジュールを使用します。このモジュールがあれば認証つきのNuxtアプリを簡単に作成できます。",[73,1864,1867],{"href":1865,"rel":1866},"https:\u002F\u002Fdev.auth.nuxtjs.org\u002F",[582],"本家のドキュメント","に習いながら進めましょう。",[1689,1870,1871],{"id":1871},"モジュールのインストール",[10,1873,1874],{},"nuxt.jsのプロジェクトルートに移動いして以下のモジュールをインストールします。",[83,1876,1879],{"className":1877,"code":1878,"language":458},[455],"npm install @nuxtjs\u002Fauth-next @nuxtjs\u002Faxios\n",[51,1880,1878],{"__ignoreMap":89},[1689,1882,1884],{"id":1883},"nuxtconfigjsでの設定","nuxt.config.jsでの設定",[10,1886,1887,1890],{},[51,1888,1889],{},"nuxt.config.js","でまずモジュールの読み込みをします。",[83,1892,1895],{"className":1893,"code":1894,"language":458},[455],"...javascript[nuxt.config.js]\n\u002F\u002F Modules (https:\u002F\u002Fgo.nuxtjs.dev\u002Fconfig-modules)\n  modules: [\n    '@nuxtjs\u002Faxios',\n    '@nuxtjs\u002Fauth'\n  ],\n...\n",[51,1896,1894],{"__ignoreMap":89},[10,1898,1899],{},"これでauthモジュールとaxiosモジュールが使えます。authモジュールはstoreを使用しますので、storeにindex.jsがない場合は空でもいいので作っていきます。",[10,1901,1902,1903,1905],{},"そしてauthモジュールの設定を",[51,1904,1889],{},"で行います。",[83,1907,1911],{"className":1908,"code":1909,"filename":1889,"language":1910,"meta":89,"style":89},"language-javascript shiki shiki-themes material-theme-ocean","...\nauth:{\n    localStorage: false,\n    strategies:{\n      local:{\n        tokenType:'bearer',\n        endpoints:{\n          login:{\n            url:'\u002Fauth\u002Flogin',\n            method:'post',\n            propertyName:'access_token'\n          },\n          logout:{\n            url:'\u002Fauth\u002Flogout',\n            method:'post',\n          },\n          user:{\n            url:'\u002Fauth\u002Fme',\n            method:'get',\n            propertyName:false\n          }\n        }\n      },\n      redirect: {\n        login: '\u002Flogin',\n        logout: '\u002F',\n        callback: '\u002Flogin',\n        home: '\u002Fhome'\n      }\n}\n...\n","javascript",[51,1912,1913,1917,1926,1939,1946,1953,1970,1977,1984,2000,2016,2030,2035,2042,2057,2071,2075,2082,2097,2112,2121,2126,2130,2135,2145,2161,2177,2192,2206,2211,2215],{"__ignoreMap":89},[93,1914,1915],{"class":95,"line":96},[93,1916,1084],{"class":103},[93,1918,1919,1923],{"class":95,"line":117},[93,1920,1922],{"class":1921},"s5Dmg","auth",[93,1924,1925],{"class":103},":{\n",[93,1927,1928,1931,1933,1936],{"class":95,"line":129},[93,1929,1930],{"class":1921},"    localStorage",[93,1932,104],{"class":103},[93,1934,1935],{"class":258}," false",[93,1937,1938],{"class":103},",\n",[93,1940,1941,1944],{"class":95,"line":138},[93,1942,1943],{"class":1921},"    strategies",[93,1945,1925],{"class":103},[93,1947,1948,1951],{"class":95,"line":149},[93,1949,1950],{"class":1921},"      local",[93,1952,1925],{"class":103},[93,1954,1955,1958,1960,1963,1966,1968],{"class":95,"line":159},[93,1956,1957],{"class":1921},"        tokenType",[93,1959,104],{"class":103},[93,1961,1962],{"class":103},"'",[93,1964,1965],{"class":110},"bearer",[93,1967,1962],{"class":103},[93,1969,1938],{"class":103},[93,1971,1972,1975],{"class":95,"line":168},[93,1973,1974],{"class":1921},"        endpoints",[93,1976,1925],{"class":103},[93,1978,1979,1982],{"class":95,"line":178},[93,1980,1981],{"class":1921},"          login",[93,1983,1925],{"class":103},[93,1985,1986,1989,1991,1993,1996,1998],{"class":95,"line":186},[93,1987,1988],{"class":1921},"            url",[93,1990,104],{"class":103},[93,1992,1962],{"class":103},[93,1994,1995],{"class":110},"\u002Fauth\u002Flogin",[93,1997,1962],{"class":103},[93,1999,1938],{"class":103},[93,2001,2002,2005,2007,2009,2012,2014],{"class":95,"line":194},[93,2003,2004],{"class":1921},"            method",[93,2006,104],{"class":103},[93,2008,1962],{"class":103},[93,2010,2011],{"class":110},"post",[93,2013,1962],{"class":103},[93,2015,1938],{"class":103},[93,2017,2018,2021,2023,2025,2028],{"class":95,"line":202},[93,2019,2020],{"class":1921},"            propertyName",[93,2022,104],{"class":103},[93,2024,1962],{"class":103},[93,2026,2027],{"class":110},"access_token",[93,2029,114],{"class":103},[93,2031,2032],{"class":95,"line":212},[93,2033,2034],{"class":103},"          },\n",[93,2036,2037,2040],{"class":95,"line":226},[93,2038,2039],{"class":1921},"          logout",[93,2041,1925],{"class":103},[93,2043,2044,2046,2048,2050,2053,2055],{"class":95,"line":238},[93,2045,1988],{"class":1921},[93,2047,104],{"class":103},[93,2049,1962],{"class":103},[93,2051,2052],{"class":110},"\u002Fauth\u002Flogout",[93,2054,1962],{"class":103},[93,2056,1938],{"class":103},[93,2058,2059,2061,2063,2065,2067,2069],{"class":95,"line":250},[93,2060,2004],{"class":1921},[93,2062,104],{"class":103},[93,2064,1962],{"class":103},[93,2066,2011],{"class":110},[93,2068,1962],{"class":103},[93,2070,1938],{"class":103},[93,2072,2073],{"class":95,"line":262},[93,2074,2034],{"class":103},[93,2076,2077,2080],{"class":95,"line":273},[93,2078,2079],{"class":1921},"          user",[93,2081,1925],{"class":103},[93,2083,2084,2086,2088,2090,2093,2095],{"class":95,"line":281},[93,2085,1988],{"class":1921},[93,2087,104],{"class":103},[93,2089,1962],{"class":103},[93,2091,2092],{"class":110},"\u002Fauth\u002Fme",[93,2094,1962],{"class":103},[93,2096,1938],{"class":103},[93,2098,2099,2101,2103,2105,2108,2110],{"class":95,"line":291},[93,2100,2004],{"class":1921},[93,2102,104],{"class":103},[93,2104,1962],{"class":103},[93,2106,2107],{"class":110},"get",[93,2109,1962],{"class":103},[93,2111,1938],{"class":103},[93,2113,2114,2116,2118],{"class":95,"line":299},[93,2115,2020],{"class":1921},[93,2117,104],{"class":103},[93,2119,2120],{"class":258},"false\n",[93,2122,2123],{"class":95,"line":310},[93,2124,2125],{"class":103},"          }\n",[93,2127,2128],{"class":95,"line":321},[93,2129,1374],{"class":103},[93,2131,2132],{"class":95,"line":332},[93,2133,2134],{"class":103},"      },\n",[93,2136,2137,2140,2142],{"class":95,"line":343},[93,2138,2139],{"class":1921},"      redirect",[93,2141,104],{"class":103},[93,2143,2144],{"class":103}," {\n",[93,2146,2147,2150,2152,2154,2157,2159],{"class":95,"line":352},[93,2148,2149],{"class":1921},"        login",[93,2151,104],{"class":103},[93,2153,107],{"class":103},[93,2155,2156],{"class":110},"\u002Flogin",[93,2158,1962],{"class":103},[93,2160,1938],{"class":103},[93,2162,2163,2166,2168,2170,2173,2175],{"class":95,"line":364},[93,2164,2165],{"class":1921},"        logout",[93,2167,104],{"class":103},[93,2169,107],{"class":103},[93,2171,2172],{"class":110},"\u002F",[93,2174,1962],{"class":103},[93,2176,1938],{"class":103},[93,2178,2179,2182,2184,2186,2188,2190],{"class":95,"line":373},[93,2180,2181],{"class":1921},"        callback",[93,2183,104],{"class":103},[93,2185,107],{"class":103},[93,2187,2156],{"class":110},[93,2189,1962],{"class":103},[93,2191,1938],{"class":103},[93,2193,2194,2197,2199,2201,2204],{"class":95,"line":381},[93,2195,2196],{"class":1921},"        home",[93,2198,104],{"class":103},[93,2200,107],{"class":103},[93,2202,2203],{"class":110},"\u002Fhome",[93,2205,114],{"class":103},[93,2207,2208],{"class":95,"line":391},[93,2209,2210],{"class":103},"      }\n",[93,2212,2213],{"class":95,"line":873},[93,2214,985],{"class":103},[93,2216,2217],{"class":95,"line":878},[93,2218,1084],{"class":103},[10,2220,2221],{},"ここでは予めauthモジュールで使用するログイン用のルートを指定したり、使用する通信パターンを定義します。",[10,2223,2224,2225,2228,2229,2232],{},"JWTトークンをローカルストレージに入れておくのは危ないらしいので、",[51,2226,2227],{},"localStorage: false","としておきます。そして",[51,2230,2231],{},"strategies","の中で通信パターンやルートの定義を行います。",[10,2234,2235,2236,2239],{},"今は",[51,2237,2238],{},"local","という通信パターンしかありませんが、outhとかapi2とか他のapiサーバーに対しての通信パターンを複数定義できます。",[10,2241,2242,2245,2246,2249,2250,2253,2254,2256,2257,2260],{},[51,2243,2244],{},"tokenType","で先ほどの",[51,2247,2248],{},"beare","を指定しておきます。こうすると自動的に",[51,2251,2252],{},"authorization","ヘッダーに",[51,2255,2248],{},"という文字を追加してくれます。",[51,2258,2259],{},"endopoints","でそれぞれのログイン（login）、ログアウト（logout）、ユーザー確認（user）、それぞれのルートを指定します。",[10,2262,2263,2264,2267],{},"指定しないとauthモジュールのデフォルトのURLでアクセスしてしまいます。特に",[51,2265,2266],{},"user","はページが読み込みされた際に、トークンをサーバーに送ってログイン状態かどうかをNuxt.jsに伝える機能があります。ここをキチンと設定しないとNuxt側で現在ログインが必要なページが開けないなどの状態に陥ります。",[1689,2269,2270],{"id":2270},"axiosの設定",[10,2272,2273],{},"最後にaxiosの設定をします。",[83,2275,2277],{"className":1908,"code":2276,"filename":1889,"language":1910,"meta":89,"style":89},"const ENV = require('dotenv').config().parsed;\nexport default {\n... \nenv:ENV,\naxios: {\n    baseURL: ENV.API_BASE_URL,\n  },\n...\n}\n",[51,2278,2279,2325,2336,2343,2350,2359,2376,2381,2385],{"__ignoreMap":89},[93,2280,2281,2285,2288,2291,2295,2298,2300,2303,2305,2308,2311,2314,2317,2319,2322],{"class":95,"line":96},[93,2282,2284],{"class":2283},"sJ14y","const",[93,2286,2287],{"class":125}," ENV ",[93,2289,2290],{"class":103},"=",[93,2292,2294],{"class":2293},"sdLwU"," require",[93,2296,2297],{"class":125},"(",[93,2299,1962],{"class":103},[93,2301,2302],{"class":110},"dotenv",[93,2304,1962],{"class":103},[93,2306,2307],{"class":125},")",[93,2309,2310],{"class":103},".",[93,2312,2313],{"class":2293},"config",[93,2315,2316],{"class":125},"()",[93,2318,2310],{"class":103},[93,2320,2321],{"class":125},"parsed",[93,2323,2324],{"class":103},";\n",[93,2326,2327,2331,2334],{"class":95,"line":117},[93,2328,2330],{"class":2329},"s6cf3","export",[93,2332,2333],{"class":2329}," default",[93,2335,2144],{"class":103},[93,2337,2338,2341],{"class":95,"line":129},[93,2339,2340],{"class":103},"...",[93,2342,126],{"class":125},[93,2344,2345,2348],{"class":95,"line":138},[93,2346,2347],{"class":125},"env:ENV",[93,2349,1938],{"class":103},[93,2351,2352,2355,2357],{"class":95,"line":149},[93,2353,2354],{"class":99},"axios",[93,2356,104],{"class":103},[93,2358,2144],{"class":103},[93,2360,2361,2364,2366,2369,2371,2374],{"class":95,"line":159},[93,2362,2363],{"class":99},"    baseURL",[93,2365,104],{"class":103},[93,2367,2368],{"class":125}," ENV",[93,2370,2310],{"class":103},[93,2372,2373],{"class":125},"API_BASE_URL",[93,2375,1938],{"class":103},[93,2377,2378],{"class":95,"line":168},[93,2379,2380],{"class":103},"  },\n",[93,2382,2383],{"class":95,"line":178},[93,2384,1084],{"class":103},[93,2386,2387],{"class":95,"line":186},[93,2388,985],{"class":103},[10,2390,2391,2392,2394,2395,2398,2399,2401],{},"nuxtのdotenvモジュールを用いて",[51,2393,524],{},"ファイルから",[51,2396,2397],{},"baseURL","つまりAPIのアクセス先ルートを指定します。",[51,2400,524],{},"は以下のようになっています。",[83,2403,2406],{"className":2404,"code":2405,"filename":524,"language":458,"meta":89},[455],"API_BASE_URL=http:\u002F\u002Flocalhost:8000\u002Fapi\u002Fv1\n",[51,2407,2405],{"__ignoreMap":89},[10,2409,2410,2411,2413,2414,2416,2417,2419],{},"今はローカルの開発環境でやっていますが本番は",[51,2412,1850],{},"ではなくドメインになったりします。環境ごとに異なる値は",[51,2415,524],{},"に記述して環境ごとに",[51,2418,524],{},"ファイルを作成してそれをインポートします。",[67,2421,2422],{"id":2422},"ログインフォームを整える",[10,2424,2425],{},"デフォルトのページとかを削除してログインフォームとかを用意します。今回はbootstrapで構築しました。このようにヘッダーがあり、「ログイン」をクリックすると入力モーダルが現れます。",[39,2427],{":src":2428,":width":1654},"'_mix\u002Fsch-2020-12-05-15.07.38-768x389.png'",[39,2430],{":src":2431,":width":1654},"'_mix\u002Fsch-2020-12-05-15.09.41-768x529.png'",[10,2433,2434,2435,2438],{},"この送信をクリックするとnuxt authの関数、",[51,2436,2437],{},"loginwith()","が実行されます。コンポーネントレベルですが以下のコードになっています。",[83,2440,2445],{"className":2441,"code":2442,"filename":2443,"language":2444,"meta":89,"style":89},"language-vue shiki shiki-themes material-theme-ocean","\u003Ctemplate>\n    \u003Cb-modal\n      id=\"login-modal\"\n      ref=\"modal\"\n      title=\"ログイン情報を入力してください。\"\n      ok-only\n      :okTitle=\"'送信'\"\n      @show=\"resetModal\"\n      @hidden=\"resetModal\"\n      @ok=\"handleOk\"\n    >\n      \u003Cform @submit.stop.prevent=\"handleSubmit\">\n        \u003Cb-alert v-if=\"loginErrMes\" show variant=\"danger\">{{loginErrMes}}\u003C\u002Fb-alert>\n        \u003Cb-form-group\n          :state=\"emailState\"\n          label=\"メールアドレス\"\n          type=\"email\"\n          label-for=\"name-input\"\n          invalid-feedback=\"メールアドレスは入力必須です。\"\n        >\n          \u003Cb-form-input\n            id=\"login-email-input\"\n            v-model=\"email\"\n            :state=\"emailState\"\n            required\n          \u002F>\n        \u003C\u002Fb-form-group>\n\n        \u003Cb-form-group\n          :state=\"passState\"\n          label=\"パスワード\"\n          label-for=\"name-input\"\n          invalid-feedback=\"パスワードは入力必須です。\"\n          autocomplete=\"username\"\n        >\n          \u003Cb-form-input\n            id=\"login-password-input\"\n            v-model=\"pass\"\n            type=\"password\"\n            :state=\"passState\"\n            autocomplete=\"current-password\"\n            required\n          \u002F>\n        \u003C\u002Fb-form-group>\n      \u003C\u002Fform>\n    \u003C\u002Fb-modal>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport { required, minLength, between } from 'vuelidate\u002Flib\u002Fvalidators'\nexport default {\n    name:'loginModal',\n    data(){\n        return{\n            email:'',\n            pass:'',\n            emailState:null,\n            passState:null,\n            loginErrMes:null,\n        }\n    },\n    validations:{\n      email:{\n        required,\n      },\n      pass:{\n        required\n      },\n    },\n    methods:{\n        checkFormHasError(){\n            this.emailState = !this.$v.email.$invalid;\n            this.passState = !this.$v.pass.$invalid;\n            return this.$v.$invalid;\n        },\n        resetModal(){\n            this.email='';\n            this.pass='';\n            this.emailState=null;\n            this.passState=null;\n            this.loginErrMes=null;\n        },\n        handleOk(bvModalEvt){\n            bvModalEvt.preventDefault()\n            this.handleSubmit();\n        },\n        async handleSubmit() {\n            if(this.checkFormHasError()) return;\n\n            try{\n              await this.$auth.loginWith('local', { data:{\n                email:this.email,\n                password:this.pass\n              }})\n              this.resetModal();\n              this.$store.dispatch('message\u002FsetFlashMessage',{\n                content:'ログインしました。',\n                messageType:'success'\n              })\n              this.$bvModal.hide('login-modal')\n            }catch(error){\n              this.loginErrMes='パスワードまたはメールアドレスが異なります。';\n            }\n        }\n    },\n}\n","component\u002FloginModal","vue",[51,2446,2447,2458,2466,2481,2495,2509,2514,2528,2542,2555,2569,2574,2596,2644,2651,2665,2679,2693,2707,2721,2726,2734,2748,2761,2774,2779,2784,2794,2798,2804,2817,2830,2842,2855,2869,2873,2879,2892,2905,2919,2931,2945,2949,2953,2961,2970,2980,2988,2992,3001,3036,3044,3060,3068,3075,3087,3098,3106,3113,3120,3124,3129,3136,3143,3150,3154,3161,3166,3170,3174,3181,3188,3215,3237,3253,3258,3265,3277,3289,3298,3306,3314,3318,3332,3346,3357,3362,3375,3397,3402,3410,3443,3456,3467,3476,3488,3513,3530,3545,3553,3576,3594,3612,3618,3623,3628],{"__ignoreMap":89},[93,2448,2449,2452,2455],{"class":95,"line":96},[93,2450,2451],{"class":103},"\u003C",[93,2453,2454],{"class":99},"template",[93,2456,2457],{"class":103},">\n",[93,2459,2460,2463],{"class":95,"line":117},[93,2461,2462],{"class":103},"    \u003C",[93,2464,2465],{"class":99},"b-modal\n",[93,2467,2468,2471,2473,2476,2479],{"class":95,"line":129},[93,2469,2470],{"class":2283},"      id",[93,2472,2290],{"class":103},[93,2474,2475],{"class":103},"\"",[93,2477,2478],{"class":110},"login-modal",[93,2480,223],{"class":103},[93,2482,2483,2486,2488,2490,2493],{"class":95,"line":138},[93,2484,2485],{"class":2283},"      ref",[93,2487,2290],{"class":103},[93,2489,2475],{"class":103},[93,2491,2492],{"class":110},"modal",[93,2494,223],{"class":103},[93,2496,2497,2500,2502,2504,2507],{"class":95,"line":149},[93,2498,2499],{"class":2283},"      title",[93,2501,2290],{"class":103},[93,2503,2475],{"class":103},[93,2505,2506],{"class":110},"ログイン情報を入力してください。",[93,2508,223],{"class":103},[93,2510,2511],{"class":95,"line":159},[93,2512,2513],{"class":2283},"      ok-only\n",[93,2515,2516,2519,2521,2523,2526],{"class":95,"line":168},[93,2517,2518],{"class":2283},"      :okTitle",[93,2520,2290],{"class":103},[93,2522,2475],{"class":103},[93,2524,2525],{"class":110},"'送信'",[93,2527,223],{"class":103},[93,2529,2530,2533,2535,2537,2540],{"class":95,"line":178},[93,2531,2532],{"class":2283},"      @show",[93,2534,2290],{"class":103},[93,2536,2475],{"class":103},[93,2538,2539],{"class":110},"resetModal",[93,2541,223],{"class":103},[93,2543,2544,2547,2549,2551,2553],{"class":95,"line":186},[93,2545,2546],{"class":2283},"      @hidden",[93,2548,2290],{"class":103},[93,2550,2475],{"class":103},[93,2552,2539],{"class":110},[93,2554,223],{"class":103},[93,2556,2557,2560,2562,2564,2567],{"class":95,"line":194},[93,2558,2559],{"class":2283},"      @ok",[93,2561,2290],{"class":103},[93,2563,2475],{"class":103},[93,2565,2566],{"class":110},"handleOk",[93,2568,223],{"class":103},[93,2570,2571],{"class":95,"line":202},[93,2572,2573],{"class":103},"    >\n",[93,2575,2576,2579,2582,2585,2587,2589,2592,2594],{"class":95,"line":212},[93,2577,2578],{"class":103},"      \u003C",[93,2580,2581],{"class":99},"form",[93,2583,2584],{"class":2283}," @submit.stop.prevent",[93,2586,2290],{"class":103},[93,2588,2475],{"class":103},[93,2590,2591],{"class":110},"handleSubmit",[93,2593,2475],{"class":103},[93,2595,2457],{"class":103},[93,2597,2598,2601,2604,2607,2609,2611,2614,2616,2619,2622,2624,2626,2629,2631,2634,2637,2640,2642],{"class":95,"line":226},[93,2599,2600],{"class":103},"        \u003C",[93,2602,2603],{"class":99},"b-alert",[93,2605,2606],{"class":2283}," v-if",[93,2608,2290],{"class":103},[93,2610,2475],{"class":103},[93,2612,2613],{"class":110},"loginErrMes",[93,2615,2475],{"class":103},[93,2617,2618],{"class":2283}," show",[93,2620,2621],{"class":2283}," variant",[93,2623,2290],{"class":103},[93,2625,2475],{"class":103},[93,2627,2628],{"class":110},"danger",[93,2630,2475],{"class":103},[93,2632,2633],{"class":103},">",[93,2635,2636],{"class":125},"{{loginErrMes}}",[93,2638,2639],{"class":103},"\u003C\u002F",[93,2641,2603],{"class":99},[93,2643,2457],{"class":103},[93,2645,2646,2648],{"class":95,"line":238},[93,2647,2600],{"class":103},[93,2649,2650],{"class":99},"b-form-group\n",[93,2652,2653,2656,2658,2660,2663],{"class":95,"line":250},[93,2654,2655],{"class":2283},"          :state",[93,2657,2290],{"class":103},[93,2659,2475],{"class":103},[93,2661,2662],{"class":110},"emailState",[93,2664,223],{"class":103},[93,2666,2667,2670,2672,2674,2677],{"class":95,"line":262},[93,2668,2669],{"class":2283},"          label",[93,2671,2290],{"class":103},[93,2673,2475],{"class":103},[93,2675,2676],{"class":110},"メールアドレス",[93,2678,223],{"class":103},[93,2680,2681,2684,2686,2688,2691],{"class":95,"line":273},[93,2682,2683],{"class":2283},"          type",[93,2685,2290],{"class":103},[93,2687,2475],{"class":103},[93,2689,2690],{"class":110},"email",[93,2692,223],{"class":103},[93,2694,2695,2698,2700,2702,2705],{"class":95,"line":281},[93,2696,2697],{"class":2283},"          label-for",[93,2699,2290],{"class":103},[93,2701,2475],{"class":103},[93,2703,2704],{"class":110},"name-input",[93,2706,223],{"class":103},[93,2708,2709,2712,2714,2716,2719],{"class":95,"line":291},[93,2710,2711],{"class":2283},"          invalid-feedback",[93,2713,2290],{"class":103},[93,2715,2475],{"class":103},[93,2717,2718],{"class":110},"メールアドレスは入力必須です。",[93,2720,223],{"class":103},[93,2722,2723],{"class":95,"line":299},[93,2724,2725],{"class":103},"        >\n",[93,2727,2728,2731],{"class":95,"line":310},[93,2729,2730],{"class":103},"          \u003C",[93,2732,2733],{"class":99},"b-form-input\n",[93,2735,2736,2739,2741,2743,2746],{"class":95,"line":321},[93,2737,2738],{"class":2283},"            id",[93,2740,2290],{"class":103},[93,2742,2475],{"class":103},[93,2744,2745],{"class":110},"login-email-input",[93,2747,223],{"class":103},[93,2749,2750,2753,2755,2757,2759],{"class":95,"line":332},[93,2751,2752],{"class":2283},"            v-model",[93,2754,2290],{"class":103},[93,2756,2475],{"class":103},[93,2758,2690],{"class":110},[93,2760,223],{"class":103},[93,2762,2763,2766,2768,2770,2772],{"class":95,"line":343},[93,2764,2765],{"class":2283},"            :state",[93,2767,2290],{"class":103},[93,2769,2475],{"class":103},[93,2771,2662],{"class":110},[93,2773,223],{"class":103},[93,2775,2776],{"class":95,"line":352},[93,2777,2778],{"class":2283},"            required\n",[93,2780,2781],{"class":95,"line":364},[93,2782,2783],{"class":103},"          \u002F>\n",[93,2785,2786,2789,2792],{"class":95,"line":373},[93,2787,2788],{"class":103},"        \u003C\u002F",[93,2790,2791],{"class":99},"b-form-group",[93,2793,2457],{"class":103},[93,2795,2796],{"class":95,"line":381},[93,2797,620],{"emptyLinePlaceholder":619},[93,2799,2800,2802],{"class":95,"line":391},[93,2801,2600],{"class":103},[93,2803,2650],{"class":99},[93,2805,2806,2808,2810,2812,2815],{"class":95,"line":873},[93,2807,2655],{"class":2283},[93,2809,2290],{"class":103},[93,2811,2475],{"class":103},[93,2813,2814],{"class":110},"passState",[93,2816,223],{"class":103},[93,2818,2819,2821,2823,2825,2828],{"class":95,"line":878},[93,2820,2669],{"class":2283},[93,2822,2290],{"class":103},[93,2824,2475],{"class":103},[93,2826,2827],{"class":110},"パスワード",[93,2829,223],{"class":103},[93,2831,2832,2834,2836,2838,2840],{"class":95,"line":883},[93,2833,2697],{"class":2283},[93,2835,2290],{"class":103},[93,2837,2475],{"class":103},[93,2839,2704],{"class":110},[93,2841,223],{"class":103},[93,2843,2844,2846,2848,2850,2853],{"class":95,"line":888},[93,2845,2711],{"class":2283},[93,2847,2290],{"class":103},[93,2849,2475],{"class":103},[93,2851,2852],{"class":110},"パスワードは入力必須です。",[93,2854,223],{"class":103},[93,2856,2857,2860,2862,2864,2867],{"class":95,"line":894},[93,2858,2859],{"class":2283},"          autocomplete",[93,2861,2290],{"class":103},[93,2863,2475],{"class":103},[93,2865,2866],{"class":110},"username",[93,2868,223],{"class":103},[93,2870,2871],{"class":95,"line":899},[93,2872,2725],{"class":103},[93,2874,2875,2877],{"class":95,"line":904},[93,2876,2730],{"class":103},[93,2878,2733],{"class":99},[93,2880,2881,2883,2885,2887,2890],{"class":95,"line":909},[93,2882,2738],{"class":2283},[93,2884,2290],{"class":103},[93,2886,2475],{"class":103},[93,2888,2889],{"class":110},"login-password-input",[93,2891,223],{"class":103},[93,2893,2894,2896,2898,2900,2903],{"class":95,"line":915},[93,2895,2752],{"class":2283},[93,2897,2290],{"class":103},[93,2899,2475],{"class":103},[93,2901,2902],{"class":110},"pass",[93,2904,223],{"class":103},[93,2906,2907,2910,2912,2914,2917],{"class":95,"line":921},[93,2908,2909],{"class":2283},"            type",[93,2911,2290],{"class":103},[93,2913,2475],{"class":103},[93,2915,2916],{"class":110},"password",[93,2918,223],{"class":103},[93,2920,2921,2923,2925,2927,2929],{"class":95,"line":926},[93,2922,2765],{"class":2283},[93,2924,2290],{"class":103},[93,2926,2475],{"class":103},[93,2928,2814],{"class":110},[93,2930,223],{"class":103},[93,2932,2933,2936,2938,2940,2943],{"class":95,"line":931},[93,2934,2935],{"class":2283},"            autocomplete",[93,2937,2290],{"class":103},[93,2939,2475],{"class":103},[93,2941,2942],{"class":110},"current-password",[93,2944,223],{"class":103},[93,2946,2947],{"class":95,"line":937},[93,2948,2778],{"class":2283},[93,2950,2951],{"class":95,"line":943},[93,2952,2783],{"class":103},[93,2954,2955,2957,2959],{"class":95,"line":949},[93,2956,2788],{"class":103},[93,2958,2791],{"class":99},[93,2960,2457],{"class":103},[93,2962,2963,2966,2968],{"class":95,"line":955},[93,2964,2965],{"class":103},"      \u003C\u002F",[93,2967,2581],{"class":99},[93,2969,2457],{"class":103},[93,2971,2972,2975,2978],{"class":95,"line":960},[93,2973,2974],{"class":103},"    \u003C\u002F",[93,2976,2977],{"class":99},"b-modal",[93,2979,2457],{"class":103},[93,2981,2982,2984,2986],{"class":95,"line":966},[93,2983,2639],{"class":103},[93,2985,2454],{"class":99},[93,2987,2457],{"class":103},[93,2989,2990],{"class":95,"line":971},[93,2991,620],{"emptyLinePlaceholder":619},[93,2993,2994,2996,2999],{"class":95,"line":977},[93,2995,2451],{"class":103},[93,2997,2998],{"class":99},"script",[93,3000,2457],{"class":103},[93,3002,3003,3006,3009,3012,3015,3018,3020,3023,3026,3029,3031,3034],{"class":95,"line":982},[93,3004,3005],{"class":2329},"import",[93,3007,3008],{"class":103}," {",[93,3010,3011],{"class":125}," required",[93,3013,3014],{"class":103},",",[93,3016,3017],{"class":125}," minLength",[93,3019,3014],{"class":103},[93,3021,3022],{"class":125}," between",[93,3024,3025],{"class":103}," }",[93,3027,3028],{"class":2329}," from",[93,3030,107],{"class":103},[93,3032,3033],{"class":110},"vuelidate\u002Flib\u002Fvalidators",[93,3035,114],{"class":103},[93,3037,3038,3040,3042],{"class":95,"line":1458},[93,3039,2330],{"class":2329},[93,3041,2333],{"class":2329},[93,3043,2144],{"class":103},[93,3045,3046,3049,3051,3053,3056,3058],{"class":95,"line":1464},[93,3047,3048],{"class":99},"    name",[93,3050,104],{"class":103},[93,3052,1962],{"class":103},[93,3054,3055],{"class":110},"loginModal",[93,3057,1962],{"class":103},[93,3059,1938],{"class":103},[93,3061,3062,3065],{"class":95,"line":1469},[93,3063,3064],{"class":99},"    data",[93,3066,3067],{"class":103},"(){\n",[93,3069,3070,3073],{"class":95,"line":1475},[93,3071,3072],{"class":2329},"        return",[93,3074,786],{"class":103},[93,3076,3077,3080,3082,3085],{"class":95,"line":1480},[93,3078,3079],{"class":99},"            email",[93,3081,104],{"class":103},[93,3083,3084],{"class":103},"''",[93,3086,1938],{"class":103},[93,3088,3089,3092,3094,3096],{"class":95,"line":1486},[93,3090,3091],{"class":99},"            pass",[93,3093,104],{"class":103},[93,3095,3084],{"class":103},[93,3097,1938],{"class":103},[93,3099,3100,3103],{"class":95,"line":1491},[93,3101,3102],{"class":99},"            emailState",[93,3104,3105],{"class":103},":null,\n",[93,3107,3108,3111],{"class":95,"line":1496},[93,3109,3110],{"class":99},"            passState",[93,3112,3105],{"class":103},[93,3114,3115,3118],{"class":95,"line":1501},[93,3116,3117],{"class":99},"            loginErrMes",[93,3119,3105],{"class":103},[93,3121,3122],{"class":95,"line":1507},[93,3123,1374],{"class":103},[93,3125,3126],{"class":95,"line":1512},[93,3127,3128],{"class":103},"    },\n",[93,3130,3131,3134],{"class":95,"line":1517},[93,3132,3133],{"class":99},"    validations",[93,3135,1925],{"class":103},[93,3137,3138,3141],{"class":95,"line":1522},[93,3139,3140],{"class":99},"      email",[93,3142,1925],{"class":103},[93,3144,3145,3148],{"class":95,"line":1528},[93,3146,3147],{"class":125},"        required",[93,3149,1938],{"class":103},[93,3151,3152],{"class":95,"line":1533},[93,3153,2134],{"class":103},[93,3155,3156,3159],{"class":95,"line":1539},[93,3157,3158],{"class":99},"      pass",[93,3160,1925],{"class":103},[93,3162,3163],{"class":95,"line":1544},[93,3164,3165],{"class":125},"        required\n",[93,3167,3168],{"class":95,"line":1549},[93,3169,2134],{"class":103},[93,3171,3172],{"class":95,"line":1554},[93,3173,3128],{"class":103},[93,3175,3176,3179],{"class":95,"line":1560},[93,3177,3178],{"class":99},"    methods",[93,3180,1925],{"class":103},[93,3182,3183,3186],{"class":95,"line":1565},[93,3184,3185],{"class":99},"        checkFormHasError",[93,3187,3067],{"class":103},[93,3189,3190,3193,3195,3198,3201,3204,3206,3208,3210,3213],{"class":95,"line":1571},[93,3191,3192],{"class":103},"            this.",[93,3194,2662],{"class":125},[93,3196,3197],{"class":103}," =",[93,3199,3200],{"class":103}," !this.",[93,3202,3203],{"class":125},"$v",[93,3205,2310],{"class":103},[93,3207,2690],{"class":125},[93,3209,2310],{"class":103},[93,3211,3212],{"class":125},"$invalid",[93,3214,2324],{"class":103},[93,3216,3217,3219,3221,3223,3225,3227,3229,3231,3233,3235],{"class":95,"line":1576},[93,3218,3192],{"class":103},[93,3220,2814],{"class":125},[93,3222,3197],{"class":103},[93,3224,3200],{"class":103},[93,3226,3203],{"class":125},[93,3228,2310],{"class":103},[93,3230,2902],{"class":125},[93,3232,2310],{"class":103},[93,3234,3212],{"class":125},[93,3236,2324],{"class":103},[93,3238,3239,3242,3245,3247,3249,3251],{"class":95,"line":1581},[93,3240,3241],{"class":2329},"            return",[93,3243,3244],{"class":103}," this.",[93,3246,3203],{"class":125},[93,3248,2310],{"class":103},[93,3250,3212],{"class":125},[93,3252,2324],{"class":103},[93,3254,3255],{"class":95,"line":1586},[93,3256,3257],{"class":103},"        },\n",[93,3259,3260,3263],{"class":95,"line":1592},[93,3261,3262],{"class":99},"        resetModal",[93,3264,3067],{"class":103},[93,3266,3267,3269,3271,3273,3275],{"class":95,"line":1597},[93,3268,3192],{"class":103},[93,3270,2690],{"class":125},[93,3272,2290],{"class":103},[93,3274,3084],{"class":103},[93,3276,2324],{"class":103},[93,3278,3279,3281,3283,3285,3287],{"class":95,"line":1603},[93,3280,3192],{"class":103},[93,3282,2902],{"class":125},[93,3284,2290],{"class":103},[93,3286,3084],{"class":103},[93,3288,2324],{"class":103},[93,3290,3291,3293,3295],{"class":95,"line":1609},[93,3292,3192],{"class":103},[93,3294,2662],{"class":125},[93,3296,3297],{"class":103},"=null;\n",[93,3299,3300,3302,3304],{"class":95,"line":1615},[93,3301,3192],{"class":103},[93,3303,2814],{"class":125},[93,3305,3297],{"class":103},[93,3307,3308,3310,3312],{"class":95,"line":1621},[93,3309,3192],{"class":103},[93,3311,2613],{"class":125},[93,3313,3297],{"class":103},[93,3315,3316],{"class":95,"line":1627},[93,3317,3257],{"class":103},[93,3319,3320,3323,3325,3329],{"class":95,"line":1632},[93,3321,3322],{"class":99},"        handleOk",[93,3324,2297],{"class":103},[93,3326,3328],{"class":3327},"s7ZW3","bvModalEvt",[93,3330,3331],{"class":103},"){\n",[93,3333,3335,3338,3340,3343],{"class":95,"line":3334},84,[93,3336,3337],{"class":125},"            bvModalEvt",[93,3339,2310],{"class":103},[93,3341,3342],{"class":2293},"preventDefault",[93,3344,3345],{"class":99},"()\n",[93,3347,3349,3351,3353,3355],{"class":95,"line":3348},85,[93,3350,3192],{"class":103},[93,3352,2591],{"class":2293},[93,3354,2316],{"class":99},[93,3356,2324],{"class":103},[93,3358,3360],{"class":95,"line":3359},86,[93,3361,3257],{"class":103},[93,3363,3365,3368,3371,3373],{"class":95,"line":3364},87,[93,3366,3367],{"class":2283},"        async",[93,3369,3370],{"class":99}," handleSubmit",[93,3372,2316],{"class":103},[93,3374,2144],{"class":103},[93,3376,3378,3381,3383,3386,3389,3392,3395],{"class":95,"line":3377},88,[93,3379,3380],{"class":2329},"            if",[93,3382,2297],{"class":99},[93,3384,3385],{"class":103},"this.",[93,3387,3388],{"class":2293},"checkFormHasError",[93,3390,3391],{"class":99},"()) ",[93,3393,3394],{"class":2329},"return",[93,3396,2324],{"class":103},[93,3398,3400],{"class":95,"line":3399},89,[93,3401,620],{"emptyLinePlaceholder":619},[93,3403,3405,3408],{"class":95,"line":3404},90,[93,3406,3407],{"class":2329},"            try",[93,3409,786],{"class":103},[93,3411,3413,3416,3418,3421,3423,3426,3428,3430,3432,3434,3436,3438,3441],{"class":95,"line":3412},91,[93,3414,3415],{"class":2329},"              await",[93,3417,3244],{"class":103},[93,3419,3420],{"class":125},"$auth",[93,3422,2310],{"class":103},[93,3424,3425],{"class":2293},"loginWith",[93,3427,2297],{"class":99},[93,3429,1962],{"class":103},[93,3431,2238],{"class":110},[93,3433,1962],{"class":103},[93,3435,3014],{"class":103},[93,3437,3008],{"class":103},[93,3439,3440],{"class":99}," data",[93,3442,1925],{"class":103},[93,3444,3446,3449,3452,3454],{"class":95,"line":3445},92,[93,3447,3448],{"class":99},"                email",[93,3450,3451],{"class":103},":this.",[93,3453,2690],{"class":125},[93,3455,1938],{"class":103},[93,3457,3459,3462,3464],{"class":95,"line":3458},93,[93,3460,3461],{"class":99},"                password",[93,3463,3451],{"class":103},[93,3465,3466],{"class":125},"pass\n",[93,3468,3470,3473],{"class":95,"line":3469},94,[93,3471,3472],{"class":103},"              }}",[93,3474,3475],{"class":99},")\n",[93,3477,3479,3482,3484,3486],{"class":95,"line":3478},95,[93,3480,3481],{"class":103},"              this.",[93,3483,2539],{"class":2293},[93,3485,2316],{"class":99},[93,3487,2324],{"class":103},[93,3489,3491,3493,3496,3498,3501,3503,3505,3508,3510],{"class":95,"line":3490},96,[93,3492,3481],{"class":103},[93,3494,3495],{"class":125},"$store",[93,3497,2310],{"class":103},[93,3499,3500],{"class":2293},"dispatch",[93,3502,2297],{"class":99},[93,3504,1962],{"class":103},[93,3506,3507],{"class":110},"message\u002FsetFlashMessage",[93,3509,1962],{"class":103},[93,3511,3512],{"class":103},",{\n",[93,3514,3516,3519,3521,3523,3526,3528],{"class":95,"line":3515},97,[93,3517,3518],{"class":99},"                content",[93,3520,104],{"class":103},[93,3522,1962],{"class":103},[93,3524,3525],{"class":110},"ログインしました。",[93,3527,1962],{"class":103},[93,3529,1938],{"class":103},[93,3531,3533,3536,3538,3540,3543],{"class":95,"line":3532},98,[93,3534,3535],{"class":99},"                messageType",[93,3537,104],{"class":103},[93,3539,1962],{"class":103},[93,3541,3542],{"class":110},"success",[93,3544,114],{"class":103},[93,3546,3548,3551],{"class":95,"line":3547},99,[93,3549,3550],{"class":103},"              }",[93,3552,3475],{"class":99},[93,3554,3556,3558,3561,3563,3566,3568,3570,3572,3574],{"class":95,"line":3555},100,[93,3557,3481],{"class":103},[93,3559,3560],{"class":125},"$bvModal",[93,3562,2310],{"class":103},[93,3564,3565],{"class":2293},"hide",[93,3567,2297],{"class":99},[93,3569,1962],{"class":103},[93,3571,2478],{"class":110},[93,3573,1962],{"class":103},[93,3575,3475],{"class":99},[93,3577,3579,3582,3585,3587,3590,3592],{"class":95,"line":3578},101,[93,3580,3581],{"class":103},"            }",[93,3583,3584],{"class":2329},"catch",[93,3586,2297],{"class":99},[93,3588,3589],{"class":125},"error",[93,3591,2307],{"class":99},[93,3593,786],{"class":103},[93,3595,3597,3599,3601,3603,3605,3608,3610],{"class":95,"line":3596},102,[93,3598,3481],{"class":103},[93,3600,2613],{"class":125},[93,3602,2290],{"class":103},[93,3604,1962],{"class":103},[93,3606,3607],{"class":110},"パスワードまたはメールアドレスが異なります。",[93,3609,1962],{"class":103},[93,3611,2324],{"class":103},[93,3613,3615],{"class":95,"line":3614},103,[93,3616,3617],{"class":103},"            }\n",[93,3619,3621],{"class":95,"line":3620},104,[93,3622,1374],{"class":103},[93,3624,3626],{"class":95,"line":3625},105,[93,3627,3128],{"class":103},[93,3629,3631],{"class":95,"line":3630},106,[93,3632,985],{"class":103},[10,3634,3635,3636,3639,3640,3643],{},"このアプリでは後でいろいろフォームとかある予定なので",[51,3637,3638],{},"vuelidate","というバリデーションライブラリを入れています。このログインフォーム程度であれば必要ありませんけど。ログイン処理をしているのは下の方にある",[51,3641,3642],{},"async handleSubmit()","です。入力値が正規値であれば実行されます。",[10,3645,3646,3647,3649],{},"nuxt authは",[51,3648,1889],{},"で定義した設定を元にログインのルートにデータをPOSTします。超便利です。",[39,3651],{":src":3652,":width":1654},"'_mix\u002Fsch-2020-12-05-15.14.45-768x518.png'",[10,3654,3655],{},"先ほどテストで入れたようにシーダーのアドレスとパスワードを入れて送信します。",[39,3657],{":src":3658,":width":1654},"'_mix\u002Fsch-2020-12-05-15.17.31-768x81.png'",[10,3660,3661],{},"ネットワークを見てみるとキチンと8000ポートで待機しているlaravelへ送信されています。レスポンスが200で成功しています。クッキーを見てみるとトークンが保存されているのが分かります。",[39,3663],{":src":3664,":width":1654},"'_mix\u002Fsch-2020-12-05-15.16.35-768x71.png'",[10,3666,3667],{},"そしてユーザー情報があるか＝ログインしているかで「ログイン」を「ログアウト」を制御しています。",[39,3669],{":src":3670,":width":1654},"'_mix\u002Fsch-2020-12-05-15.22.55-768x168.png'",[10,3672,3673],{},"authモジュールを入れている場合は以下のコードでログインしているか、ユーザーの情報を取得することができます。",[83,3675,3677],{"className":1908,"code":3676,"language":1910,"meta":89,"style":89},"this.$auth.user\nthis.$auth.loggedIn\n",[51,3678,3679,3690],{"__ignoreMap":89},[93,3680,3681,3683,3685,3687],{"class":95,"line":96},[93,3682,3385],{"class":103},[93,3684,3420],{"class":125},[93,3686,2310],{"class":103},[93,3688,3689],{"class":125},"user\n",[93,3691,3692,3694,3696,3698],{"class":95,"line":117},[93,3693,3385],{"class":103},[93,3695,3420],{"class":125},[93,3697,2310],{"class":103},[93,3699,3700],{"class":125},"loggedIn\n",[31,3702,3704],{"id":3703},"nuxtのspaをビルドする","NuxtのSPAをビルドする",[10,3706,3707],{},"Nuxtは3000ポートの開発サーバで見ていたので、今度はキチンとビルドしてユーザー視点でアクセスしてみましょう。",[83,3709,3712],{"className":3710,"code":3711,"language":458},[455],"npm run build\n",[51,3713,3711],{"__ignoreMap":89},[10,3715,3716,3717,3719,3720,3722],{},"distファイルが出されたのを確認し",[51,3718,405],{},"へアクセスします。私の環境ではホストの",[51,3721,405],{},"はコンテナのlocalhost:80につながります。最初の設定の通り、ドキュメントルート はdist配下に通じているのでindex.htmlが返されます。ログインが成功し、ネットワークでもAPIが送信されているのが分かります。",[39,3724],{":src":3725,":width":1654},"'_mix\u002Fsch-2020-12-05-15.34.55-768x213.png'",[10,3727,3728],{},"後はどんどんAPIルートを作成して、nuxtからはaxiosを用いてトークン付きリクエストを送れば認証ルートにアクセスすることができます。これでJWT認証つきのSPAアプリの設定が完了しました。",[31,3730,3732],{"id":3731},"以上","以上！",[10,3734,3735],{},"以上がLravel6とNuxt.jsで構築するJWT認証つきSPAの構築です。サーバーの構成は人によって様々ですがバーチャルホスト で公開側ページとAPIを分けてしまうのが簡単な気がします。とにかくトークン認証を用いたSPAを構築する際には",[3737,3738,3739,3743,3746,3749,3752,3755,3758,3761],"ul",{},[3740,3741,3742],"li",{},"Nuxt側とAPI側でサーバーを分ける",[3740,3744,3745],{},"laravelにJWT認証ライブラリを入れる",[3740,3747,3748],{},"ログイン用ルートを整える",[3740,3750,3751],{},"CORSの設定を行う",[3740,3753,3754],{},"NuxtからのログインルートにPOSTリクエストを送る",[3740,3756,3757],{},"トークンをブラウザのクッキーなどに保存",[3740,3759,3760],{},"認証ルートにはリクエストヘッダにBeare＋トークンでリクエストをする",[3740,3762,3763],{},"おのつど、またはページがリロードされたら \u002Fapi\u002Fauth\u002Fmeでトークンが有効かを確かめてNuxt側に認証状態を知らせる。",[10,3765,3766],{},"以上のまとめを意識すればおおよそのNuxt+API認証はわかってくると思います。ReactとかNext.jsなどもこの部分のエッセンスは同じなのでぜひ応用してください。",[31,3768,3769],{"id":3769},"参考記事",[3737,3771,3772,3779,3786],{},[3740,3773,3774],{},[73,3775,3778],{"href":3776,"rel":3777},"https:\u002F\u002Fpgmemo.tokyo\u002Fdata\u002Farchives\u002F1703.html",[582],"Laravel6 に jwt-auth をインストールしSPAからログインする（バックエンド Laravel編）",[3740,3780,3781],{},[73,3782,3785],{"href":3783,"rel":3784},"https:\u002F\u002Fgithub.com\u002Ftymondesigns\u002Fjwt-auth\u002Fissues\u002F2059",[582],"Tymon\\JWTAuth\\Exceptions\\JWTException: Could not create token: Implicit conversion of keys from strings is deprecated. Please use InMemory or LocalFileReference classes. ",[3740,3787,3788],{},[73,3789,3791],{"href":1865,"rel":3790},[582],"Nuxt auth introduction",[3793,3794,3795],"style",{},"html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}",{"title":89,"searchDepth":129,"depth":129,"links":3797},[3798,3803,3807,3816,3817,3830,3831,3832],{"id":33,"depth":117,"text":34,"children":3799},[3800,3801,3802],{"id":69,"depth":129,"text":69},{"id":447,"depth":129,"text":448},{"id":482,"depth":129,"text":483},{"id":489,"depth":117,"text":490,"children":3804},[3805,3806],{"id":493,"depth":129,"text":493},{"id":515,"depth":129,"text":516},{"id":542,"depth":117,"text":543,"children":3808},[3809,3810,3811,3812,3813,3814,3815],{"id":557,"depth":129,"text":558},{"id":587,"depth":129,"text":587},{"id":700,"depth":129,"text":700},{"id":727,"depth":129,"text":728},{"id":988,"depth":129,"text":989},{"id":1146,"depth":129,"text":1147},{"id":1211,"depth":129,"text":1211},{"id":1640,"depth":117,"text":1641},{"id":1680,"depth":117,"text":1681,"children":3818},[3819,3824,3829],{"id":1684,"depth":129,"text":1684,"children":3820},[3821,3822,3823],{"id":1691,"depth":138,"text":1692},{"id":1701,"depth":138,"text":1702},{"id":1731,"depth":138,"text":1732},{"id":1858,"depth":129,"text":1859,"children":3825},[3826,3827,3828],{"id":1871,"depth":138,"text":1871},{"id":1883,"depth":138,"text":1884},{"id":2270,"depth":138,"text":2270},{"id":2422,"depth":129,"text":2422},{"id":3703,"depth":117,"text":3704},{"id":3731,"depth":117,"text":3732},{"id":3769,"depth":117,"text":3769},[3834],"devstack","2025-09-05","md",null,{},"\u002Farticles\u002Flaravel-nuxt-jwt-spa",{"title":5,"description":5},"articles\u002Flaravel-nuxt-jwt-spa",[436,3843],"nuxt","_mix\u002Flaravel-nuxt.jpeg","PoGyyswEs82YuxYkbUxf6PSHnouWa2M9g-hxfKYHTNE",1780987141443]