【 APIキー 開発 】Go言語による自作WebAPIに原始的な APIキー 認証機能を実装する

今回は自作のWebAPIに APIキー 認証機能を実装します。様々なツールやライブラリもありますが、今回はそのようなものは使わず、最低限の認証機能をプログラミングだけで作成します。Web通信に0からAPIキー認証機能を実装したいという方の参考になれれば幸いです。

## 土台となるAPI

今回APIキーを実装させるAPIは、前に作ったGo言語・RESTAPI・SendGridによるお問い合わせメールAPIです。作り方や使用は[こちら](https://qiita.com/haruki-lo-shelon/items/3ed239d5479f84b10384)の記事から参照できます。（少しプログラムに変更点もあります。詳しいコードは[GitHub](https://github.com/haruki-lo-shelon/go_sendEmail2)に掲載）

https://qiita.com/haruki-lo-shelon/items/3ed239d5479f84b10384

https://github.com/haruki-lo-shelon/go_sendEmail2

## APIキー が必要な理由

このAPIは、お問い合わせメールの内容をJson形式でpostして、受け取ったデータをSendGridを使って指定した宛先にメールとして送信するというものでした。

これをインターネットのサーバーで公開したとき、悪意のある人間が大量のデータをpostすることで、サーバーをダウンさせたり無駄に通信量を消費してAWSのサービス料金が多くかかってしまったりすることを防ぐ必要がありました。

それを防ぐ最も簡単な方法としてAPIキーの実装があります。APIキーは決して高いセキュリティ性を発揮するものではありませんが、みだりにデータを送信されるようなことはある程度防げるかと思います。

## 今回作成した APIキー の仕様

今回作成したAPIキーはとても簡単なもので、Content-TypeヘッダのJson形式で送られてくるお問い合わせのテキスト内容や送り主のメールアドレスのデータのほかにもう一つ、AuthorizationヘッダでAPIキーをPostします。

そしてその送られてきたAPIキーが、隠しファイルで設定したAPIキーと一致すればメールを作成・送信して、一致しなければエラー処理を起こすというものです。

ものすごく原始的ですがシンプルで簡単でした。

## 実装

まず、.envファイルにAPIキーを設定します。

~~~
API_KEY=your_api_key #←ここにSendGridのAPIキーを入力
TOS=you@youremail.com,friend1@friendemail.com,friend2@friendemail.com
# TOSにはメールが届いてほしいメールアドレスを入れる。「,」で区切ることで複数指定できる。
# とりあえず「,」は使わずに、メールアドレスは一つでいい。

Tokumemo_API_KEY=ランダムな文字列 #テキトーにキーボードを叩くなりして複雑な文字列を設定
# Tokumemoは前回作成したAPIの名前なのでスルーしてください
~~~

後はmain処理でAPIキーを検証するだけです。

今回のお問い合わせAPIでは、postされたデータを処理するプログラムファイルは「PostEmail.go」となっているのでそちらに書いていきます。

~~~go:PostEmail.go
package handler

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"github.com/joho/godotenv"

	"github.com/ant0ine/go-json-rest/rest"
	"net/http"
)

//メールの構造体
type Email struct {
	Text    string
	Email   string
}

//メールを送信する関数
func PostEmail(w rest.ResponseWriter, r *rest.Request) {

  //送られてきたAuthorizationヘッダのデータ（APIキー）を取り出す
	Sent_Tokumemo_API_KEY := r.Header["Authorization"]

	SendToEmail := Email{}

  //SendToEmailにpost値を入れる
	err := r.DecodeJsonPayload(&SendToEmail)
	if err != nil {
			rest.Error(w, err.Error(), http.StatusInternalServerError)
			return
	}
	
   ：
  省略
   ：

	// .envから環境変数読み込み
	SendGrid_API_KEY := os.Getenv("SendGrid_API_KEY")
	TOS := strings.Split(os.Getenv("TOS"), ",")
	fr := SendToEmail.Email//postした値に含めたメールアドレス（送信者のメアド）
	Tokumemo_API_KEY := os.Getenv("Tokumemo_API_KEY")

  ---ここからAPIキー認証プログラム---

	//TokumemoのAPIキーを検証
	if Sent_Tokumemo_API_KEY[0] != Tokumemo_API_KEY {
		rest.Error(w, "correct apiKey required", 400)
		return
	}

  ---APIキー認証プログラムここまで！---

   ：
  省略
   ：

	// メール送信を行い、レスポンスを表示
	client := sendgrid.NewSendClient(SendGrid_API_KEY)
	response, err := client.Send(message)
	if err != nil {
		log.Println(err)
	} else {
		fmt.Println(response.StatusCode)
		fmt.Println(response.Body)
		fmt.Println(response.Headers)
	}
	w.WriteJson(&SendToEmail)
}
~~~

## APIキー 認証の仕組み

このプログラムコードだけでは分かりにくいかもですが、仕組みを理解すれば実装は簡単です。

１．まず「送られてきたAuthorizationヘッダのデータ（APIキー）を取り出す」の部分のr.Header[“Authorization”]でAuthorizationヘッダを持つデータの値を取得してSent_Tokumemo_API_KEY[]に格納します。今回はここに送信者が送ったAPIキーが入っています。

２．そして「.envから環境変数読み込み」の部分で.envファイルで設定したAPIキーを変数Tokumemo_API_KEYに格納しています。

３．最後に「TokumemoのAPIキーを検証」の部分で、送信されてきたAPIキー（Sent_Tokumemo_API_KEY）と正しいAPIキー（Tokumemo_API_KEY）をif文で比較してエラー処理を書きます。

この一連の処理を、メール送信の本処理の前に書くことで、APIキー認証機能を実装することができました。

## 動作確認

では動作確認をします。

コマンドプロンプトで「go run main.go」を実行して、もう一つのコマンドプロンプトでcurlによるpost送信をします。データがContent-TypeとAuthorizationの２つあることに注意です。

    curl -i -H "Content-Type: application/json" -d "{\"Text\":\"hello!!\",\"Email\":\"example@email.com\"}" -H "Authorization: .envのTokumemo_API_KEYに設定した文字列"  http://localhost:8080/post

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/bd7ee925-c385-1cfd-7525-28bac7058598.png)
このようになっていれば認証成功です。メールも確認してみましょう。

もしAPIキーが一致しなければ、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/f7e85771-c4ee-a297-a237-fa1fae66947c.png)
となります。