Golangで認証サーバーを立てる

今回は、認証サーバーを立て、加えてReact(front-side)との連携方法を学んだ記録になります。下の記事を参照しながら、すすめていきます。

前提として、

  • Goがインストール済みであり、Tour of Go(チュートリアルサイト)を経ていること。
  • go-plusがATOMにインストール済であること。
  • Reactを少し使ったことがある。
  • gorilla/mux(routerの管理)とgorilla/handlers(middleware)がインストール済みであること。

まず初めにmain.go(実行)ファイルを書いていき、APIをつくります。

package main をファイルの一行目に書き、importするdependenciesはautoで入力されていることを前提にします。

main.go

//Product is doing as catalog of VR
type Product struct {
Id int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
}
//products is a slice of Product information
var products = []Product{
Product{Id: 1, Name: "Hover Shooters", Slug: "hover-shooters", Description: "Shoot your way to the top on 14 different hoverboards"},
Product{Id: 2, Name: "Ocean Explorer", Slug: "ocean-explorer", Description: "Explore the depths of the sea in this one of a kind underwater experience"},
Product{Id: 3, Name: "Dinosaur Park", Slug: "dinosaur-park", Description: "Go back 65 million years in the past and ride a T-Rex"},
Product{Id: 4, Name: "Cars VR", Slug: "cars-vr", Description: "Get behind the wheel of the fastest cars in the world."},
Product{Id: 5, Name: "Robin Hood", Slug: "robin-hood", Description: "Pick up the bow and arrow and master the art of archery"},
Product{Id: 6, Name: "Real World VR", Slug: "real-world-vr", Description: "Explore the seven wonders of the world in VR"},
}

上のデータは今回のアプリケーションに使用するJSON形式のデータになります。

次にmain関数を下の様に書きます。

func main() {
r := mux.NewRouter()
r.Handle("/", http.FileServer(http.Dir("./views/")))
//it makes a setup so we can use static assets from /static/{file} routes
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
r.Handle("/get-token", GetTokenHandler).Methods("GET")
r.Handle("/products", jwtMiddleware.Handler(ProductsHandler)).Methods("GET") r.Handle("/products/{slug}/feedback", jwtMiddleware.Handler(AddFeedbackHandler)).Methods("POST")
http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, r))
}

処理の流れとしては、

  1. ルーターを起動して
  2. ルートパスを通ったら、./views/フォルダにいくことを設定
  3. staticフォルダのassetsにパスを通して
  4. /get-token エンドポイントをGETで通ったら、GetTokenHandler(ある特定の処理)を通るように設定。
    以下、/products エンドポイントも同様。
  5. ポートを3000番に設定して、どのhandlerを通っても、その処理のログが出力されるようにする。

また、各handler(GetTokenHandler/ProductsHandler/AddFeedbackHandler)は次の様になります。

main.go

/* Set up a global string for our secret */
var mySigningKey = []byte("secret")
/* Handlers */
var GetTokenHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
/* Create the token */
token := jwt.New(jwt.SigningMethodHS256)
// Create a map to store our claims
claims := token.Claims.(jwt.MapClaims)
/* Set token claims */
claims["admin"] = true
claims["name"] = "Ado Kukic"
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
/* Sign the token with our secret */
tokenString, _ := token.SignedString(mySigningKey)
/* Finally, write the token to the browser window */
w.Write([]byte(tokenString))
})
var jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
return mySigningKey, nil
},
SigningMethod: jwt.SigningMethodHS256,
})

上記のコードは、トークンを生成し、それらのトークンにクレームを追加することを可能にします。 この例では、トークンを取得するための認証は必要なく、後々Auth0を用いてAPIの認証機能をつけていきます。

jwtMiddleware はtokenの検証する関数になります。

var ProductsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
payload, _ := json.Marshal(products)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(payload))
})
var AddFeedbackHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var product Product
vars := mux.Vars(r)
slug := vars["slug"]
for _, p := range products {
if p.Slug == slug {
product = p
}
}
w.Header().Set("Content-Type", "application/json")
if product.Slug != "" {
payload, _ := json.Marshal(product)
w.Write([]byte(payload))
} else {
w.Write([]byte("product not found"))
}
})

上の2つは、基本的には同じ処理内容になります。

  1. products(JSONデータ)をMarshalして、payload変数にいれ
  2. headerをJSONタイプに設定したら、そのpayload変数(JSONデータ)を出力します。

また、 AddFeedbackHandler 関数に関しては、HTTPリクエストにslugが入っていないときには、エラーが出る処理がされています。


上のコードをmain.goファイルに書き終えたら、同じproject内に./staticと./viewsフォルダを作ります。

staticフォルダに、次のindex.htmlファイルを入れ、JWTが機能しているか確認していきます。

index.html

<!DOCTYPE html>
<head>
<title>We R VR</title>
</head>
<body>
<h1>Welcome to We R VR</h1>
</body>

確認方法

  1. Postmanをインストールする
  2. go run main.go をうち、ブラウザでlocalhost:3000/productsを見た時に、Required Authorization token not foundの表示をみる
  3. localhost:3000/get-tokenでトークンを表示させ
  4. Postmanでlocalhost:3000/productsをみて返ってくるAPIがproducts(JSONデータ)であることを確認する。その際には、headerに、keyをAuthorization、valueをBearer {/get-tokenで表示されるtoken}を与える必要があります。

ここまで、GolangでJSON Webトークンを使用する方法を簡単に説明していきました。 次のチュートリアルでは、Auth0を使用したエンドツーエンド認証を実装します。

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.