https://d226lax1qjow5r.cloudfront.net/blog/blogposts/implement-multi-factor-authentication-in-go-with-verify/blog_go_verify2_1200x600.png

Verify を使用した囲碁での多要素認証の実装

最終更新日 November 13, 2020

所要時間:1 分

何百万人ものユーザーを抱えるプロジェクトであろうと、小さなサイドプロジェクトであろうと、構築するアプリケーションが安全でセキュアであることを保証することが最も重要です。安全でないアプリケーションは、ユーザーデータをハッカーにさらす可能性があり、結果としてお金と信頼を失うことになります。ソフトウェア開発者の仕事は、書かれているコードがセキュリティ第一のアプローチをとり、すべての緩い部分が説明されていることを確認することです。アプリケーションのセキュリティを確保する1つの方法は、一般的にMFAと呼ばれる多要素認証システムを統合することです。

多要素認証は、アプリケーションにセキュリティを追加するだけでなく、ユーザーの身元を確認するためにも使用されます。この記事では、Go プログラミング言語と Vonage Verify API を使用して MFA システムを実装する方法を説明します。.

前提条件

この記事に従うには、以下のものが必要だ:

  • 囲碁(バージョン1.14以上)

  • 囲碁モジュール有効

  • お好みのテキストエディタ

  • 囲碁の基礎知識

Vonage API アカウント

このチュートリアルを完了するには Vonage APIアカウント.まだお持ちでない方は 今すぐサインアップをクリックし、無料のクレジットを使用して構築を開始することができます。アカウントを取得すると、APIキーとAPIシークレットが Vonage APIダッシュボード.

プロジェクト設定

認証コードを生成し、ユーザー提供の電話番号に送信するシンプルなアプリケーションを作成します。ユーザーは確認ページでコードを入力し、アプリケーションはそれが有効かどうかを確認します。

App workflowApp workflow

上の画像は、この記事で作るアプリケーションのワークフローの大まかなスケッチである。

まず、以下のツリー構造に合わせてファイルとフォルダを作成します:

├── static/ │ ├── index.html │ ├── form.html ├── .env ├── utils/ │ ├── verify.go └── server.go

静的フォルダには、ユーザーの電話番号と確認コードをそれぞれ収集するために使用される2つのHTMLページ(フォーム)が含まれています。

Envファイルは、環境変数や非公開の値を保存するために使われる。この .envファイルには Vonage API Key と Secret が含まれます。 ダッシュボード.

ディレクトリには utilsディレクトリには verify.goファイルがあり、Vonage Verify API に直接関連するすべてのコードが格納されています。プロジェクトのルートにある server.goファイルには、HTML ファイルを提供するサーバに関連するロジックが含まれます。

ビューの設定

ウェブ・アプリケーションを作成する最初のステップは、HTMLフォームを提供するシンプルなウェブ・サーバーを作成することです。この server.goファイルに以下を含めます:

func main() {
//Create the fileServer Handler
   fileServer := http.FileServer(http.Dir("./static"))
//Create a New Serve Mux to register handler
   mux := http.NewServeMux()
   mux.Handle("/", fileServer)
//Create the server on Port 8080 and print start message!
   fmt.Printf("Starting server at port 8080\n")
   log.Fatal(http.ListenAndServe(":8080", mux))
}

をインポートし net/http packageをインポートし、その FileServer関数を呼び出します。 staticディレクトリへのルートを最初の引数として渡す。この http.FileServer関数は、URLパターンに登録するハンドラを返します。ハンドラを登録するには、関数 http.NewServeMux関数を使用して新しい serve mux を作成し、その Handleメソッドを呼び出します。 /をパターンとして、上記で生成したファイルサーバーハンドラーとともに渡す。次に http.ListenAndServeメソッドを使ってサーバーを作成する。ポート番号と上記で作成したserve muxを渡し、ターミナルにメッセージを表示してサーバーが稼動していることを知らせます。

ファイルを実行すると server.goファイルを実行すると、サーバーが起動したことを示す起動メッセージが表示される。しかし localhost:8080/にアクセスすると、空白のページが表示されるだけです。これは index.htmlファイルが空だからです。

index.html fileというタイトルのフォームを作成します。 登録というタイトルのフォームを作成します:

<form method="POST" action="/form">
   <h2>Register</h2>
   <label>Please Input your phone number:</label><br/>
   <input name="phone" type="tel" required value="" >
   <input type="submit" value="Submit">
</form>

サーバーはユーザーが提供するデータを受け取るので、フォームのメソッドは POST です。フォームのアクションをルートに設定します、 /formに設定します。このルートは登録フォームから返されたデータを処理するために用意されます。

最初の登録ページが準備できたので、ユーザーに送信されるコードの確認のための2番目のページを作ることができます。確認ページは登録ページと似ていますが、フィールドと入力のラベルを少し変更するだけです:

<form method="POST" action="/confirm">
   <h2>Confirm Phone Number</h2>
   <label for="phonenum">Please Input the confirmation code sent to your phone:</label><br/>
   <input id="phonenum" name="confirmation" type="tel" required value="" >
   <input name="phone" type="hidden" value="{{ .Phone }}">
   <input name="requestId" type="hidden" value="{{ .Id }}">
   <input type="submit" value="Submit">
</form>

両方のHTMLファイルの全文は サンプル・レポ.両方のHTMLファイルを設定したら、サーバーを再起動してください。すべてがうまくいっていれば index.htmlブラウザで localhost:8080にアクセスすると、ファイルが表示されるはずです。

Registration formRegistration form

電話番号を入力して送信ボタンをクリックすると、先ほどHTMLアクション属性で指定した localhost:8080/formにリダイレクトされることがわかります。この /formルートは現在 form.htmlファイルを提供するように設定されていません。次のセクションでは /formルートのハンドラーを作成します。 confirm.htmlファイルをレンダリングします。

多要素認証の導入

このセクションでは、アプリケーションの核となる多要素認証について説明し、それをコード化します。Vonage Verify API を使用して多要素認証を実装します。

Verify APIでMFAを実装するプロセスは、双方向のプロセスである:

  • 最初のステップはVerifyリクエストを開始することである。この段階で、ユーザーの携帯電話にコードが送信される。

  • 第二のステップは、ユーザーが提供した認証コードが正しいかどうかをチェックすることである。

Verifyリクエストが開始されると、ユーザーの電話番号から Request_idがユーザーの電話番号から自動的に生成されます。このIDは、ステップ2の検証で使用されます。

Vonageの開発者が Goパッケージパッケージを作成しました。始めるには、ターミナルで go get github.com/vonage/vonage-go-sdkを実行し、プロジェクトにインストールしてください。

さて、すべての準備が整ったところで、さっそく飛び込んでみよう!

ファイル内に verify.goファイルに4つの関数を作成する:

1. createClient

この関数には、クライアントを作成するためのロジックが含まれています。クライアントは、Verify API と対話するために必要です。クライアントを作成するには NewVerifyClient関数を呼び出します。 vonage-goパッケージが提供する関数を呼び出します。この NewVerifyClient関数を呼び出して作成します。 CreateAuthFromKeySecret関数を呼び出し、APIキーとシークレットを渡して作成します。

機密情報が悪人の手に渡るのを防ぐため、環境変数として保存するのは良い習慣だ。上記で作成した .envファイルに、APIキーとシークレットを追加する。 API_KEY=0000000.

この時点で createClient関数は次のようになる:

func createClient() *vonage.VerifyClient{
   Key, _ := os.LookupEnv("API_KEY")
   Secret, _ := os.LookupEnv("API_SECRET")
   auth := vonage.CreateAuthFromKeySecret(Key, Secret)
   client := vonage.NewVerifyClient(auth)
   return client
}

2. init関数

この init関数はGoによってあらかじめ定義されており、アプリケーションの初期化に使われます。この関数を使って、残りのコードを実行する前に環境変数を .envその前に、環境変数のロードによく使われるパッケージをインストールする必要があります。ターミナルで go get github.com/joho/godotenv' to install the package. Next, add the corresponding import. Theinitfunction will contain just a few lines of code which invokes thegodotenv` ロード関数を実行します。

func init() {
   // loads values from .env into the system
   if err := godotenv.Load(); err != nil {
      log.Print("No .env file found")
   }
}

3.Verスタート機能

この関数で検証リクエストを開始する。この関数はメイン・パッケージにエクスポートされるので、Goの標準に従って関数の最初の文字を大文字にします。関数の中では VerStart関数では、クライアント上でVonage SDKの Requestメソッドをクライアントに呼び出します。上で作成した createClient関数を呼び出します。 Requestメソッドを呼び出すことができるクライアントを取得します:

func VerStart(phoneNumber string) string{
   client := createClient()
verification, _, err := client.Request(phoneNumber, "Go-Tut MFA", vonage.VerifyOpts{
		CodeLength: 6,
	})

   if err != nil {
      log.Fatal(err)
   }
   return verification.RequestId
}

この Requestメソッドは3つのパラメータを受け取る:

  • 確認される電話番号

  • ブランド名

  • ユーザーに送信される OTP をカスタマイズするためのオプション構造体。

私たちのアプリでは、電話番号をダイナミックにしたいので、関数呼び出し時に渡される Request関数のパラメータとして指定します。ブランド名は、どのブランドがSMSを送信するかを示す短い文字列です。必要なパラメータが Requestメソッドに必要なパラメータが渡されたら、その戻り値を扱うことができます。この Requestメソッドは、ステータス・フィールド、無視するhttpレスポンス、エラー・タイプを含む検証レスポンスを返します。検証応答ステータスを返し、エラーを処理することができる。

4. verCheck関数

この関数は、ユーザーが送信した検証コードの確認に関連するロジックを格納します。この関数は verStart関数に似ています:

func VerCheck(reqId, code string) string{
   client := createClient()
   response, _, err := client.Check(reqId, code)
   if err != nil {
            log.Fatal(err)
   }
   if err != nil {
      log.Fatal(err)
   }

   return response.Status
}

この verCheck関数の必須引数であるリクエストIDと Check関数の必須引数である codeパラメータを受け取ります。この関数は文字列型のステータスを返します。返されるステータスは、ユーザが正しい確認コードを入力したかどうかを示します。ユーザが入力した確認コードが正しい場合のみ、応答ステータスは0になります。

次のセクションでは、アプリケーションを動作させるために、上記で作成した4つの関数をどこで呼び出すべきかを説明する。

アプリケーションを組み立てる

アプリケーションに必要なユーティリティ関数はすべて準備できたので、あとはそれをまとめてアプリケーションとして動作させるだけです。インデックス・ページはすでにレンダリングしましたが、送信ボタンがクリックされたときに表示される確認ページもレンダリングしなければなりません。Goでこれを行うのは、他の言語とはかなり異なります。ハンドラ関数を作成して、登録フォームのデータを受け取る /formルートにアタッチしなければなりません。次に formHandlerという関数を作成します。次に、リクエストボディをパースして index.html.このためにhttpリクエストの ParseFormメソッドを使います。

フォーム・データは、解析されたフォームから formValueメソッドを使います。このメソッドは index.htmlファイルで指定された名前を取り込みます。次に、インポートして verRequest関数を呼び出します。

ユーザーが電話番号を入力したときに確認ページを表示するには、別の関数を作成する必要がある。単に http.Servefile関数を使って form.htmlファイルを提供するために関数を使用することもできますが、私たちのケースでは理想的な解決策ではありません。確認ファイルをレンダリングするだけでなく、ユーザーの電話番号とリクエストIDを渡す必要があります。 verCheckユーティリティ関数を呼び出すために使用できるようにします。

httpリクエスト、レスポンス・ライター、インターフェイスを受け取ります。レンダー関数はGoの http/templateパッケージを使ってファイルを解析し、提供されたデータ(ユーザーの電話番号とリクエストID)を使って実行する。

func render(w http.ResponseWriter, filename string, data interface{}) {
//parse the provided file
   tmpl, err := template.ParseFiles(filename)
   if err != nil {
      log.Println(err)
   }
//execute the file
   if err := tmpl.Execute(w, data); err != nil {
      log.Println(err)
   }
}

レンダー関数の準備ができたら、フォームファイルへのルートとメッセージを渡して formHandler関数を呼び出すことができます。メッセージを渡すには、form.html ファイルに渡すフィールドを定義した構造体を作成します:

type Message struct {
   Phone  string
   Id     string
}

ファイルに隠しフィールドを作り、メッセージ構造体の変数を受け取るようにしなければならない。 form.htmlファイルに隠しフィールドを作成して、メッセージ構造体の変数を受け取るようにしなければならない:

<input name="phone" type="hidden" value="{{ .Phone }}">
<input name="requestId" type="hidden" value="{{ .Id }}">

この時点で formHandler関数全体は次のようになる。

func formHandler (w http.ResponseWriter, r *http.Request){
//Parse the form
      if err := r.ParseForm(); err != nil {
         fmt.Fprintf(w, "ParseForm() err: %v", err)
         return
      }
//Get the value of the Input from the form
      Phone :=  r.FormValue("phone")
      Id := verify.VerStart(Phone)
      msg := &Message{
         Id: Id,
         Phone: Phone,
      }
//Render the form.
      render(w, "./static/form.html", msg)
}

テストする前に、最後にもうひとつやっておくことがある。 formHandler関数を /formルートに登録することです。そのためにコードを1行追加するだけです:

mux.HandleFunc("/form", formHandler)

これで準備は整った!プログラムを実行し、登録ページで電話番号を入力し、送信をクリックします。送信ボタンをクリックすると、確認ページが表示され、携帯電話にSMSが届きます。

SMS codeSMS code

アプリケーションはうまくまとまりつつある。次にやるべきことは、ユーザーが確認コードを入力したときの処理です。現在のアプリケーションの状態では、ユーザーが確認コードを入力して送信をクリックすると、まだ設定されていない確認ルートにリダイレクトされます。

クライアントから確認コードを受け取って verCheckを呼び出すようにします。confirmハンドラはformハンドラとよく似ていますが、いくつかの違いがあるだけです。

始めに、ハンドラーインターフェースを実装する confirmHandler関数を作り、ハンドラーインターフェースを実装し、入ってきたリクエストを解析します。 formHandler function.次に、フォームから verCheck関数を実行するために必要な値をフォームから抽出します。抽出する値は3つあります:

  • 電話番号

  • リクエストID

  • 確認コード

最初の2つの値は formHandlerレンダー関数を使って form.html file.値を取得するには、以下の行を追加するだけです。 formHandler関数を作るときに説明した

Id := r.FormValue("requestId")
phone := r.FormValue("phone")
confirmation := r.FormValue("confirmation")

これで、ワークフローの第2ステップ(コードの検証)に必要なすべての値を 受け取った。 verCheck functionを呼び出すことができる。を呼び出すことができます。 verCheck関数が成功ステータスを返すように設定したのを覚えていますか?そのステータスをチェックして、ユーザが入力した確認コードが正しいかどうかを確認し、成功メッセージか失敗メッセージを新しいウェブページに出力するために fmt.FPrint関数を使用して、新しいウェブページに成功メッセージまたは失敗メッセージを出力することができます。この時点で confirmHandlerはこのようになるはずです:

func confirmHandler(w http.ResponseWriter, r *http.Request) {
//Parse the form
   if err := r.ParseForm(); err != nil {
      fmt.Fprintf(w, "ParseForm() err: %v", err)
      return
   }
//Extract the Form values
   Id := r.FormValue("requestId")
   phone := r.FormValue("phone")
//Receive the confirmation code
   confirmation := r.FormValue("confirmation")
//Verify the Confirmation code
   response := verify.VerCheck(Id, confirmation)
//Check if the confirmation code is incorrect
   if response != "0" {
     fmt.Fprint(w,"Verification failed! Input the correct code sent to ", phone)
      return
   }

   fmt.Fprint(w,"🎉 Success! 🎉")
}

この時点で、アプリケーションはほぼ完成した。最後にしなければならないのは confirmHandlerルートを登録することです:

mux.HandleFunc("/confirm", confirmHandler)

そして、もう大丈夫です!サーバーを起動し、ブラウザでアドレスにアクセスすると、登録フォームが表示されるはずです。電話番号を入力して送信をクリックすると、携帯電話にコードが送信されます。その後、コードを入力する確認ページに自動的にリダイレクトされます。送信すると、ページに成功が印刷されるはずです。

結論

これまで、Verify API を使用するアプリケーションを Go で作成し、Go を使用した Web 開発について学んできました。楽しんでいただけたでしょうか?このアプリケーションの このアプリケーションの完全なコードは GitHub にあります。

シェア:

https://a.storyblok.com/f/270183/400x588/18f261786d/oluwatobi-okewole.png
Oluwatobi Okewole

Oluwatobi is a software developer and writer. He loves to simplify complex topics, making them easy for anyone to understand