LoginSignup
46
33

More than 5 years have passed since last update.

フレームワーク「GIN」を使ってみた(セッション管理)

Posted at

ginを利用したセッション管理のサンプル
個人的備忘用。

github.com/gin-contrib/sessionsgithub.com/gin-contrib/sessions/cookie を利用しています。

以下、ソースです。

メイン

main.go
package main

import (
    "log"
    "net/http"
    "github.com/gin-gonic/gin"
    . "SessionInfo"
    "routes"
    "github.com/gin-contrib/sessions"
    "github.com/gin-contrib/sessions/cookie"
)

var LoginInfo SessionInfo

func main() {
    router := gin.Default()

    //テンプレートの設定
    router.LoadHTMLGlob("**/view/*.html")

    // セッションの設定
    store := cookie.NewStore([]byte("secret"))
    router.Use(sessions.Sessions("mysession", store))

    router.GET("/login", routes.GetLogin)
    router.POST("/login", routes.PostLogin)

    menu := router.Group("/menu")
    menu.Use(sessionCheck())
    {
        menu.GET("/top", routes.GetMenu)
    }
    router.POST("/logout", routes.PostLogout)

    router.Run(":8080")

}

func sessionCheck() gin.HandlerFunc {
    return func(c *gin.Context) {

        session := sessions.Default(c)
        LoginInfo.UserId = session.Get("UserId")

        // セッションがない場合、ログインフォームをだす
        if LoginInfo.UserId == nil {
            log.Println("ログインしていません")
            c.Redirect(http.StatusMovedPermanently, "/login")
            c.Abort() // これがないと続けて処理されてしまう
        } else {
            c.Set("UserId", LoginInfo.UserId) // ユーザidをセット
            c.Next()
        }
        log.Println("ログインチェック終わり")
    }
}

説明

1.セッションの宣言
セッションを扱うため、middleware router.Use を利用する

store := cookie.NewStore([]byte("secret"))
router.Use(sessions.Sessions("mysession", store))

2.セッションチェック
セッション(ログイン状態)をチェックするため、sessionCheck関数を呼び出す。
全体的にセッションチェックすると、ログイン画面で必ずエラーになってしまうため、グループ化したmiddlewareを利用している。

menu.Use(sessionCheck())

3.ログインチェック

middlewareから呼び出される。
形式は、以下のようにするのはお決まり?

ログファイルの書き出しなどに利用できるかもしれない。

func sessionCheck() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 処理前にやりたいことを記述(今回は、ログインチェック)
    c.Next()
        // 処理後にやりたいことを記述
}

セッション情報

SessionInfo/sessioninfo.go
package sessioninfo

type SessionInfo struct {
    UserId interface{}
}

説明

セッションで管理したい情報を構造体で簡易する。
今回は、ユーザIDのみ。

コントローラ

routes/routes.go
package routes

import (
    "log"
    "net/http"

    "github.com/gin-contrib/sessions"
    "github.com/gin-gonic/gin"
)

func Logout(c *gin.Context) {

    //セッションからデータを破棄する
    session := sessions.Default(c)
    log.Println("セッション取得")
    session.Clear()
    log.Println("クリア処理")
    session.Save()

}

func Login(c *gin.Context, UserId string) {

    //セッションにデータを格納する
    session := sessions.Default(c)
    session.Set("UserId", UserId)
    session.Save()
}

説明

ログイン時のセッション情報の書き込みと、ログアウト時のセッション情報をクリア処理

routes/LoginController.go
package routes

import (
    "log"
    "net/http"

    "github.com/gin-gonic/gin"
)

func GetLogin(c *gin.Context) {

    c.HTML(http.StatusOK, "login", gin.H{
        "UserId":       "",
        "ErrorMessage": "",
    })

}

func PostLogin(c *gin.Context) {
    log.Println("ログイン処理")
    UserId := c.PostForm("userId")

    Login(c, UserId) // // 同じパッケージ内のログイン処理

    c.Redirect(http.StatusMovedPermanently, "/menu/top")

}

説明

ログイン画面の表示と、ログイン実行時の処理を記述

routes/LogoutController.go
package routes

import (
    "log"
    "net/http"

    "github.com/gin-gonic/gin"
)

func PostLogout(c *gin.Context) {
    log.Println("ログアウト処理")
    Logout(c) // 同じパッケージ内のログアウト処理

    // ログインフォームに戻す
    c.HTML(http.StatusOK, "login", gin.H{
        "UserId":       "",
        "ErrorMessage": "",
    })
}

説明

ログアウト実行時の処理を記述

routes/MenuController.go
package routes

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func GetMenu(c *gin.Context) {
    UserId, _ := c.Get("UserId") // ログインユーザの取得

    c.HTML(http.StatusOK, "menu", gin.H{"UserId": UserId})
}

説明

メニュー画面の表示の処理を記述
middleware のsessionCheckで、c.Set("UserId", LoginInfo.UserId)でセットした値を、UserId, _ := c.Get("UserId")で取得している。

ビュー

Login/view/login.html
{{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><input type="submit" value="ログイン"></p>
</form>
</body>
</html>
{{end}}
Menu/view/menu.html
{{define "menu"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>メニュー</title>
</head>
<body>

{{ template "logout" . }}
        <p>メニュー1</p>
        <p>メニュー2</p>
        <p>メニュー3</p>
        <p>メニュー4</p>

</body>
</html>
{{end}}
Logout/view/logout.html
{{define "logout"}}

<form action="/logout" method="post">
    <p>ユーザーID: {{.UserId}}</p>
    <p><input type="submit" value="ログアウト"></p>
</form>
{{end}}
46
33
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
33