Go Revel ログイン周り整理

ずっと放っておいた、ログインとセッション周りについて整理。
この記事には、結論ありません。
本当の備忘録です。

github.com/revel/revel/samples/bookingサンプルより抜粋

初期処理

init.go

package controllers

import "github.com/revel/revel"

func init() {
	revel.OnAppStart(InitDB)
	revel.InterceptMethod((*GorpController).Begin, revel.BEFORE)
	revel.InterceptMethod(Application.AddUser, revel.BEFORE)
	revel.InterceptMethod(Hotels.checkUser, revel.BEFORE)
	revel.InterceptMethod((*GorpController).Commit, revel.AFTER)
	revel.InterceptMethod((*GorpController).Rollback, revel.FINALLY)
}

まず、JAVAで言うところのAOPライクにインターセプトされる。
余計な所は割愛して、

app.go

func (c Application) AddUser() revel.Result {
	if user := c.connected(); user != nil {
		c.RenderArgs["user"] = user
	}
	return nil
}

func (c Application) connected() *models.User {
	if c.RenderArgs["user"] != nil {
		return c.RenderArgs["user"].(*models.User)
	}
	if username, ok := c.Session["user"]; ok {
		return c.getUser(username)
	}
	return nil
}

func (c Application) getUser(username string) *models.User {
	users, err := c.Txn.Select(models.User{}, `select * from User where Username = ?`, username)
	if err != nil {
		panic(err)
	}
	if len(users) == 0 {
		return nil
	}
	return users[0].(*models.User)
}

AddUser以下関数実行して、c.RenderArgs["user"]にuser(ログイン者)を保存している。
RenderArgs http://revel.github.io/docs/src/controller.html
package revel にある。

当然、初回起動時にはログイン者なしなので、nilが返ってくる。
ログインしてれば、c.Session["user"]内の値(username)を使ってuserオブジェクトを取得しc.RenderArgs["user"]に保存。


次のインターセプタへ
hotel.go

func (c Hotels) checkUser() revel.Result {
	if user := c.connected(); user == nil {
		c.Flash.Error("Please log in first")
		return c.Redirect(routes.Application.Index())
	}
	return nil
}

この関数は、ログインしているかのチェックをしているらしい。
ログインしてないと、強制的にログイン画面へ遷移
ログインしていれば、nilを返している。

インターセプターだと戻り値nilでなにもしない??
関数じゃいかんのやろか?よくわからん。
・・・遷移処理を書きたい模様・・・

ログイン

func (c Application) Login(username, password string, remember bool) revel.Result {
	user := c.getUser(username)
	if user != nil {
		err := bcrypt.CompareHashAndPassword(user.HashedPassword, []byte(password))
		if err == nil {
			c.Session["user"] = username
			if remember {
				c.Session.SetDefaultExpiration()
			} else {
				c.Session.SetNoExpiration()
			}
			c.Flash.Success("Welcome, " + username)
			return c.Redirect(routes.Hotels.Index())
		}
	}

	c.Flash.Out["username"] = username
	c.Flash.Error("Login failed")
	return c.Redirect(routes.Application.Index())
}

func (c Application) Logout() revel.Result {
	for k := range c.Session {
		delete(c.Session, k)
	}
	return c.Redirect(routes.Application.Index())
}

まず、画面上には、例によってusername,passwordとログイン状態維持の為のチェックボックスの真偽値がサブミットでやってくる。
んで、まずusernameにてレコードを取得、その後、平文のpasswordを下記関数に預けてチェック

func CompareHashAndPassword

func CompareHashAndPassword(hashedPassword, password []byte) error

CompareHashAndPassword compares a bcrypt hashed password with its possible plaintext equivalent. Returns nil on success, or an error on failure.

エラー無しで、remember値に従いそれぞれのセッションスタイルにて格納。
セッションのキー"user"にusernameをいれる。


ここで、c.RenderArgs["user"]にuser入れれば良いんじゃね?とか思うけど、次画面遷移時に委譲しているみたい。
つまり、またインターセプトされて、AddUserが走るって訳。


( ;´Д`)いやぁぁぁぁぁー!面倒臭い!!