Go Signinしたときにtokenを作成する

token作成やsessionの部分でつまずいたのでメモです。
SigninしたときにGo側でtokenを作成し、Javascriptのlocalstorageでtokenの情報を保持します。
データベースにaccountsテーブルがあり、email,password,nameなどその他諸々が入ってます。


##サインイン画面
<img width="487" alt="スクリーンショット 2019-08-21 13.01.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320179/7ea529fd-38a8-a5a7-a0e9-46f7821bdf9f.png">


##Go
フレームワークとしてechoを使用しています。
トークンの中身はとりあえずaccount_idとトークンの有効期間を設定するやつです。

```Go:handler.go
func New(db *gorm.DB) http.Handler {
    e := echo.New()
    e.Use(middleware.CORS())

    h := &handler{
        DB: db,
    }
    return e
}

type token struct {
    AccountID uint
    jwt.StandardClaims
}

```

```Go:signin.go
    // 画面からメールアドレスとパスワードが送られてくるため、リクエストを受け取る構造体を用意してあげる
    type loginParam struct {
	Email    string `json:"email"`
	Password string `json:"password"`
    }

    func (h *handler) loginUser(c echo.Context) error {
	var params loginParam
	err := c.Bind(&params)
	if err != nil {
		return err
	}

    // リクエストとデータベースのemailが一致するレコードをセットする
	var account models.Account
	err = h.DB.Where("email = ?", params.Email).First(&account).Error
	if err != nil {
		return err
	}

    // リクエストされたemailをもつレコードがデータベースに存在しない場合のエラー処理
	if account.ID == 0 {
		return echo.ErrUnauthorized
	}

    // リクエストされたpasswordとデータベースのpasswordが一致しない時のエラー処理
	if params.Password != account.Password {
		return echo.ErrUnauthorized
	}

	// トークン作成
	claims := &token{
		AccountID: account.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Hour * 72).Unix(),
		},
	}

	// 暗号化してtokenにしまう
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 生成された暗号を文字列としてキーをつけてtにしまう
	t, err := token.SignedString([]byte("hogehoge"))
	if err != nil {
		return err
	}

	return c.JSON(http.StatusOK, map[string]string{"token": t})
}
```

##React
作成したtokenはlocalstorageに保持します。
emailとpasswordだけを送るようにして、リクエストが通ったらlocalstorageにトークンをセットして、トップページに飛ばします。
通らなかった場合は、emailかpasswordが間違っているというエラー文を画面に表示します。

```React:signin.js
handleSubmit() {
    return http
      .post('http://localhost:5000/login', {
        email: this.state.email,
        password: this.state.password
      })
      .then(response => {
        // 暗号化されたトークンをlocalStorageにabc_tokenというキーをつけてセット
        localStorage.setItem('abc_token', response.data.token);
        this.props.history.push(`/cust/toppage`)
        return response.data
      })
      .catch(error => {
        console.log(error)
        this.setState({
          errors: "メールアドレスもしくはパスワードに誤りがあります"
        })
      })
  }
```

リクエストを送るときに毎回headersにトークンを詰めなければいけないため、[axios](https://github.com/axios/axios)を用いて、http.jsに切り出して呼び出す形にしています。


```React:http.js
import axios from 'axios';

const API_HOST = process.env.REACT_APP_API_HOST || 'http://localhost:5000';
// localStorageからabc_tokenというキーでトークンをgetする
const http = axios.create({
  baseURL: API_HOST,
  headers: {
    Authorization: localStorage.getItem('abc_token') || ''
  }
});

export const defaultHttp = axios.create({
  headers: {
    Authorization: localStorage.getItem('abc_token') || ''
  }
});

export default http;
```

#検証
abc_tokenというキーがついた、暗号化されたtokenが保持されているのが確認できます
<img width="535" alt="スクリーンショット 2019-08-21 21.57.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320179/39531b23-84f3-0a95-d3e7-b3f2409a71ad.png">

以上です。
今回はトークンを作成するだけだったのですが、tokenに紐づくデータをGETする方法
[Go React トークンに紐づくユーザーの情報をGETする](https://qiita.com/kibaa_go/items/7cc5256900bd3b6ec8eb)
新しく記事を更新しました！！
理解が足りていなくて抜け落ちているところがあるかもしれないので、コメントで教えていただけると幸いです。