#はじめに
GolangのZinを使いログイン処理を書きました
#Login
[hoge] % tree ~/go/src/login
.
├── SessionInfo
│ └── sessioninfo.go
├── controller
│ └── Login.go
├── crypto
│ └── crypto.go
├── db
│ └── db.go
├── go.mod
├── go.sum
├── login
├── main.go
├── migrate
│ └── migrate.go
├── model
│ ├── Login.go
│ └── User.go
└── template
├── login.html
├── logout.html
├── menu.html
└── singup.html
7 directories, 15 files
##main
package main
import (
"log"
sessioninfo "login/SessionInfo"
"login/controller"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
var LoginInfo sessioninfo.SessionInfo
func main() {
engine := gin.Default()
engine.LoadHTMLGlob("template/*")
store := cookie.NewStore([]byte("select"))
engine.Use(sessions.Sessions("mysession", store))
engine.GET("/login", func(c *gin.Context) {
c.HTML(200, "login.html", gin.H{
"UserId": "",
})
})
engine.POST("/login", controller.NewLogin().LoginK)
engine.GET("/singup", func(c *gin.Context) {
c.HTML(200, "singup.html", gin.H{})
})
engine.POST("/singup", controller.NewLogin().SingUp)
menu := engine.Group("/menu")
menu.Use(sessionCheck())
{
menu.GET("/top", controller.GetMenu)
}
engine.POST("/logout", controller.PostLogout)
engine.Run(":8080")
}
func sessionCheck() gin.HandlerFunc {
return func(c *gin.Context) {
session := sessions.Default(c)
LoginInfo.Name = session.Get("name")
// セッションがない場合、ログインフォームをだす
if LoginInfo.Name == nil {
log.Println(session)
log.Println("ログインしていません")
c.Redirect(http.StatusMovedPermanently, "/login")
c.Abort() // これがないと続けて処理されてしまう
} else {
c.Set("name", LoginInfo.Name) // ユーザidをセット
c.Next()
}
log.Println("ログインチェック終わり")
}
}
##db
package db
import (
"fmt"
"os"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/joho/godotenv"
)
func Connection() *gorm.DB {
err := godotenv.Load(fmt.Sprintf("./%s.env", os.Getenv("GO_ENV")))
if err != nil {
// .env読めなかった場合の処理
}
DBMS := os.Getenv("login_DBMS")
USER := os.Getenv("login_USER")
PASS := os.Getenv("login_PASS")
DBNAME := os.Getenv("login_DBNAME")
CONNECT := USER + ":" + PASS + "@/" + DBNAME + "?parseTime=true"
db, err := gorm.Open(DBMS, CONNECT)
if err != nil {
panic(err.Error())
}
db.LogMode(true)
return db
}
##migrate
package main
import (
"login/db"
"login/model"
)
func main() {
db := db.Connection()
defer db.Close()
db.AutoMigrate(&model.Login{})
db.AutoMigrate(&model.User{})
}
##model
###DB
package model
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type Login struct {
gorm.Model
Name string `gorm:"unique; not null"`
Pass string `gorm:"not null"`
}
##crypto
package crypto
import (
"golang.org/x/crypto/bcrypt"
)
// PasswordEncrypt パスワードをhash化
func PasswordEncrypt(password string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(hash), err
}
// CompareHashAndPassword hashと非hashパスワード比較
func CompareHashAndPassword(hash, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}
##Sessions
package sessioninfo
type SessionInfo struct {
Name interface{}
}
##Controller
package controller
import (
"log"
"login/crypto"
"login/db"
"login/model"
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
)
type Login struct{}
func NewLogin() *Login {
return &Login{}
}
func LoginM(c *gin.Context, name string) {
session := sessions.Default(c)
session.Set("name", name)
session.Save()
}
func getUser(username string) model.Login {
db := db.Connection()
var user model.Login
db.First(&user, "name = ?", username)
db.Close()
return user
}
func (l *Login) LoginK(c *gin.Context) {
db := db.Connection()
defer db.Close()
log.Println("ログイン処理")
name := c.PostForm("name")
LoginM(c, name) // // 同じパッケージ内のログイン処理
dbPassword := getUser(c.PostForm("name")).Pass
log.Println(dbPassword)
// フォームから取得したユーザーパスワード
formPassword := c.PostForm("pass")
// ユーザーパスワードの比較
if err := crypto.CompareHashAndPassword(dbPassword, formPassword); err != nil {
log.Println("ログインできませんでした")
c.Abort()
} else {
log.Println("ログインできました")
c.Redirect(http.StatusMovedPermanently, "/menu/top")
}
}
func (l *Login) SingUp(c *gin.Context) {
var form Login
if err := c.Bind(&form); err != nil {
c.Abort()
} else {
username := c.PostForm("name")
password := c.PostForm("pass")
// 登録ユーザーが重複していた場合にはじく処理PasswordEncrypt
passwordEncrypt, _ := crypto.PasswordEncrypt(password)
db := db.Connection()
defer db.Close()
if err := db.Create(&model.Login{Name: username, Pass: passwordEncrypt}).GetErrors(); err != nil {
}
c.Redirect(302, "/login") }
}
func PostLogout(c *gin.Context) {
log.Println("ログアウト処理")
Logout(c) // 同じパッケージ内のログアウト処理
// ログインフォームに戻す
c.HTML(http.StatusOK, "login.html", gin.H{
"name": "",
"ErrorMessage": "",
})
}
func Logout(c *gin.Context) {
session := sessions.Default(c)
log.Println("セッション取得")
session.Clear()
log.Println("クリア処理")
session.Save()
}
func GetMenu(c *gin.Context) {
name, _ := c.Get("name") // ログインユーザの取得
c.HTML(http.StatusOK, "menu", gin.H{"name": name})
}