【Go】echoフレームワークでログイン機能を作成する

2017/03/14 白石英知
Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0Share on Tumblr0

echo
こんにちは。ユニトラストの白石です。
今回はGoで作成されたフレームワークecho(v3.0.3)でログイン機能を実装する形で紹介します。

echoとは

Go製の軽量なフレームワークの1つです。「golang echo」で使用例を検索するとjsonを返すAPIサーバーの事例が多いですが、Goのパッケージであるhtml/templateを使うことでwebアプリケーションの開発も可能です。また、echoは拡張性が高く、Middleware群によって機能を追加することができます。
 

インストール

echoは「go get github.com/labstack/echo」のコマンドで簡単にインストールすることができます。
 

コード

下記のコードがログイン機能を実装した全コードです。抜粋しながら説明をしていきます。

package main

import (
	"io"
	"github.com/labstack/echo"
	"html/template"
	"net/http"
	"html"
	"github.com/ipfans/echo-session"
)

type Template struct {
	templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
	var e = echo.New()

	//テンプレートの設定
	t := &Template{
		templates: template.Must(template.ParseGlob("static/template/*.html")),
	}

	e.Renderer = t

	//セッションを設定
	store := session.NewCookieStore([]byte("secret-key"))
        //セッション保持時間
	store.MaxAge(86400)
	e.Use(session.Sessions("ESESSION", store))

	e.GET("/login", ShowLoginHtml)
	e.POST("/login", Login)

	// ポート9000でサーバーを起動
	e.Logger.Fatal(e.Start(":9000"))

	// Let's Encrypt から証明書を自動取得してhttpsサーバーを起動
	//e.Logger.Fatal(e.StartAutoTLS(":443"))
}

type LoginForm struct {
	UserId string
	Password string
	ErrorMessage string
}

type CompleteJson struct {
	Success bool `json:"success"`
}

func ShowLoginHtml(c echo.Context) error {
	session := session.Default(c)

	loginId := session.Get("loginCompleted")
	if loginId != nil && loginId == "completed" {
		completeJson := CompleteJson{
			Success: true,
		}

		return c.JSON(http.StatusOK, completeJson)
	}

	return c.Render(http.StatusOK, "login", LoginForm{})
}

func Login(c echo.Context) error {
	loginForm := LoginForm{
		UserId: c.FormValue("userId"),
		Password: c.FormValue("password"),
	}

	userId := html.EscapeString(loginForm.UserId)
	password := html.EscapeString(loginForm.Password)

	if userId != "userId" && password != "password" {
		loginForm.ErrorMessage = "ユーザーID または パスワードが間違っています"
		return c.Render(http.StatusOK, "login", loginForm)
	}

	//セッションにデータを保存する
	session := session.Default(c)
	session.Set("loginCompleted", "completed")
	session.Save()

	completeJson := CompleteJson{
		Success: true,
	}

	return c.JSON(http.StatusOK, completeJson)
}

 

main

mainメソッドを見ていきます。
最初にechoを初期化します。

var e = echo.New()

今回はログイン画面にテンプレートを使うので、echoにテンプレートを設定します。(/static/templateディレクトリ以下のhtmlを対象にしています)

//テンプレートの設定
t := &Template{
	templates: template.Must(template.ParseGlob("static/template/*.html")),
}
e.Renderer = t

未ログインとログイン中を区別するために、Middlewareのecho-sessionを使って、ログイン情報をセッションに保持します。(echo-sessionはgo get github.com/ipfans/echo-sessionでインストールします)

//セッションを設定
store := session.NewCookieStore([]byte("secret-key"))
//セッション保持時間
store.MaxAge(86400)
e.Use(session.Sessions("ESESSION", store))

/loginにGETでアクセスをするとShowLoginHtmlメソッドが呼ばれます。

e.GET("/login", ShowLoginHtml)

/loginにPOSTでアクセスするとLoginメソッドが呼ばれます。

e.POST("/login", Login)

最後にサーバーを起動します。起動に失敗したらログが出力されます。

// ポート9000でサーバーを起動
e.Logger.Fatal(e.Start(":9000"))

 

ShowLoginHtml

ShowLoginHtmlメソッドを見ていきます。
ログイン中だった場合はJSONを返します。

ログイン中でなかった場合はlogin.htmlのテンプレートを表示します。第3引数に空の構造体を使います。(構造体のstringはnilではなく空文字です)

return c.Render(http.StatusOK, "login", LoginForm{})

 

Login

Loginメソッドを見ていきます。
フォームからpostされた値を確認して、ユーザーIDとパスワードに一致していた場合は、JSONを返します。
一致していない場合は、ShowLoginHtmlでは空だったLoginForm構造体のメンバにユーザーが入力したパラメーターとエラーメッセージを設定して、login.htmlのテンプレートを表示します。こうすることで、前回の入力とエラーメッセージが表示されます。
(今回はユーザーIDとパスワードをコードに書いていますが、ユーザーIDとsaltを使ったhash化したパスワードをDBに保存するのが適切です。)

loginForm := LoginForm{
	UserId: c.FormValue("userId"),
	Password: c.FormValue("password"),
}

loginForm.ErrorMessage = "ユーザーID または パスワードが間違っています"
return c.Render(http.StatusOK, "login", loginForm)

 

テンプレート

LoginForm.ErrorMessageが空文字でない(ne)ときに、エラーメッセージを表示します。if文の条件にはne(不一致)の他に、eq(一致)、lt(より下)、le(以下)、gt(より上)、ge(以上)があります。
詳しくは、公式ドキュメントを参照してください。

{{define "login"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>ログイン</title>
</head>
<body>
<form action="/login" method="post">
    {{if ne .ErrorMessage ""}}
    <p>{{.ErrorMessage}}</p>
    {{end}}
    <p>ユーザーID</p>
    <p><input type="text" name="userId" value="{{.UserId}}"></p>
    <p>パスワード</p>
    <p><input type="password" name="password" value="{{.Password}}"></p>
    <p><input type="submit" value="ログイン"></p>
</form>
</body>
</html>
{{end}}

 

まとめ

今回、echoを使ってログイン機能を作成しました。紹介したechoの機能は一部に過ぎません。例えば、Basic認証を設定したり、Let’s Encryptから自動で証明書を取得する機能などもあります。この機会にPHP、Javaから離れて、GoでWebアプリケーションを作成してみてはいかがでしょうか?

Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0Share on Tumblr0