サークル生やOBのみなさんが繋いでいきますので、そちらもぜひ目を通していただけると嬉しいです。Architectureの勉強をしたので、Go言語とWebアプリケーションフレームワークのEcho、ORマッパーのGORMで、JWTを使ったユーザ認証APIを作っていきます。まとめて書き過ぎな気もしますが、頑張ります。ヘッダー、ペイロード、署名の3つから構成されています。ヘッダー部分には、署名を作る際の暗号化方式などを、ペイロード部分には、認証する対象の情報(Claim)を格納します。これらをBase64でエンコードしたものと、それをもとに作成した署名を「.」で繋いだものがJWTとなります。ヘッダーとペイロード部分はBase64でエンコードしただけなので、簡単に中の情報を見ることができます。入れるデータには気をつけましょう。今回作成するAPIでは、公開鍵暗号方式の署名を用いた実装をしていきます。そのため、認証に成功すると以下のような情報を含むJWTを返すことにします。いくつか予約されているClaimがありますが、その中から今回使うものだけ簡単に説明します。予約されているもの以外は任意に指定して利用できます。発行元で一意に識別される情報。ユーザDBのIDやそれを暗号化したものを入れておけば良いと思っています。今回はDBのIDをそのまま入れて使います。1234567890,}こちらのサイトでは、簡単にJWTの中身を確認できるのでデバックなどで便利です。Architectureについては、たくさんのブログや書籍などで説明されており、僕が説明するよりそちらの方が詳しいと思いますので、詳細は省きます。Case、Entitiesと言うようにレイヤーを分け、自身より外の層の実装には依存しないようにすると言うアーキテクチャです。ArchitectureAPIの実装では、ようやく実装に移ります。実装の際に、こちらの記事を参考にさせていただいたので、ディレクトリ構成などは、ほぼ同じになっていると思います。非常に詳しく書かれていて分かりやすいと思うので、ぜひこちらも読んでみてください。Serverを構築してみる上記の記事と全く同じですが、ディレクトリとレイヤーの対応は下記のようになります。user_repository.goinfrastructureはじめにSQLを実行するGORMのインスタンスを作成します。今回はPostgreSQLを使用しています。user名、DB名、パスワードは自身の環境に合わせてください。利用した方が良いですが、今回は省略します。このディレクトリには、routingなどを行うrouter.goを作成しますが、それは他の実装が終わった後に行います。db}domainユーザの情報を持つ構造体を作成します。合わせてログイン時に使用するパラメータの構造体も作成しておきます。`json:"password"`}interfaces/database先ほどのGORMのインスタンスを用いて、実際にDBとデータのやりとりを行う層の実装を行います。result.Errorreturn}return}この時、Interfaceの層はDBの層よりも内側にあるため、GORMに実装されているルールを用いることができません。実装されている中で、Interfaceの層で利用する振る舞いを記述します。今回は以下のようにします。このように、Go言語のinterfaceで外の層の実装を記述することにより、外の層が内側のルールを用いて実装されている形で捉えることができます。このようにして、内側と外側の依存関係を正しく保つことをDIP(依存関係逆転の原則)と言うようです。通常であれば、ここで記述したinterfaceに合わせてinfrastructure/sql_handler.goに実装を修正していきますが、今回はORマッパーを使っているので、そちらの実装に合わせてinterfaceを記述しました。*gorm.DB}usecase次に、先ほど実装したinterfaces/databaseを用いてデータを取り、controllerから呼び出されるinteractorを実装していきます。interactor.UserRepository.FindByName(name)return}interfaces/databaseの層は外側の層なので、先ほどと同様にDIPを用いて依存のルールを保持します。error)}interfaces/controllersここでは、エンドポイントに対応した関数を実装していきます。今回は、Login()と認証が必要なエンドポイントで使用され、Userの情報をまとめて返すUserProfile()を作成します。JWT関係の処理には、jwt-goを利用しています。今回は公開鍵暗号方式を利用するため、Login()で秘密鍵のファイルを読み込んでいます。IDとNameをそれぞれclaimとして格納し、有効期限であるexpは現在から72時間後としました。false}EchoはFrameworkですので、Controllerよりも外にあります。そのため、これまでと同様にcontext.goを作成していきます。interface{}}infrastructureroutingの設定をします。JWTの認証のため、公開鍵のファイルを読み込む必要があります。この時、公開鍵の形式がPKCS#1もしくは、PKCS#8と言うものでないといけません。id_rsa.pub.pkcs8こんな感じのコマンドでPKCS#8の形式のファイルは生成できます。(具体的にどう言う違いがあるのか理解していないので、また勉強しておきたい...)また、EchoのGroup()を用いることで、認証の必要なエンドポイントをまとめて設定できます。e}仕上げ最後に、先ほどのrouter.goをmainになるapp.goから呼び出せば完了です。今回のAPIでは、ユーザを登録する部分を省いたため、ログインできません。そのため、GORMのAutoMigrateでテーブルを作るついでに、テストデータを作りましょう。例のごとく、DB名やユーザ名、パスワードは自身の環境に合わせてください。localhost:1323/user/profile{"ID":1,"CreatedAt":"2019-12-02T01:34:46.005091+09:00","UpdatedAt":"2019-12-02T01:34:46.005091+09:00","DeletedAt":null,"name":"Hoge","email":"hoge@example.com","password":"$2a$10$Dp2fgfQC6fczBB0GvY45QuPfE.6/U2aCzTZQF4Madx52fKqIHwmrm"}まとめ色々と要素を詰め込みすぎて、かなりの分量になってしまいました。「ここおかしいぞ」とか「ここ直した方がいいぞ」等々ありましたら、指摘していただけると嬉しいです。TwitterにリプorDMが一番反応が早いと思います。今回のコードをこちらのGitHubのリポジトリにおいてあります。よかったら参考にしてみてください。GitHub:user-auth-api-sampleTwitter:@indeaneagleowl最後まで読んでくださり、ありがとうございました。