users/login.html
{{define "users/login.html"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form method="post" action="/login">
username:<input style="align-content: center" type="text" name="username" onfocus="change()"><br/>
password:<input type="password" name="password" onfocus="change()"><br/>
<input type="submit" value="login">
</form>
<h1 id = "tag" style="color: red">{{.Message}}</h1>
</body>
<script>
function change() {
let tag = document.getElementById("tag");
tag.innerHTML="<h1></h1>";
}
</script>
</html>
{{end}}
default/index.html
{{define "default/index.html"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index页面</title>
</head>
<body>
<h1 style="color: chocolate; align-content: center">{{.Content}}</h1>
</body>
</html>
{{end}}
controllers/users.go
package controllers
import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"net/http"
)
package controllers
type Auth struct {
Username string
Password string
}
const DefaultAuthInfoKey = "AUTH"
func LoginGet() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "users/login.html", nil)
}
}
func LogoutGet() gin.HandlerFunc {
return func(ctx *gin.Context) {
session := sessions.Default(ctx)
session.Delete(DefaultAuthInfoKey)
session.Options(sessions.Options{
Path: "/",
Domain: "localhost",
MaxAge: 0,
Secure: true,
HttpOnly: false,
SameSite: 0,
})
session.Save()
ctx.Redirect(http.StatusFound, "/login")
ctx.Abort()
}
}
func LoginPost() gin.HandlerFunc {
return func(ctx *gin.Context) {
username := ctx.PostForm("username")
password := ctx.PostForm("password")
if username != "admin" || password != "admin" {
ctx.HTML(http.StatusOK, "users/login.html", gin.H{
"Message": "用户名或密码错误!",
})
ctx.Abort()
return
}
auth := Auth{Username: username, Password: password}
ctx.Set(DefaultAuthInfoKey, auth)
session := sessions.Default(ctx)
session.Set(DefaultAuthInfoKey, auth)
session.Save()
ctx.Redirect(http.StatusFound, "/")
}
}
func Index() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "default/index.html", gin.H{
"Content": "欢迎回来:" + ctx.MustGet(DefaultAuthInfoKey).(Auth).Username,
})
}
}
routers/router.go
package routers
import (
"encoding/gob"
"github.com/coolbit/gin_sample/controllers"
"github.com/coolbit/gin_sample/middleware"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"net/http"
)
var router *gin.Engine
func GetRouter() *gin.Engine {
return router
}
func AuthRequired() gin.HandlerFunc {
return func(ctx *gin.Context) {
session := sessions.Default(ctx)
auth := session.Get(controllers.DefaultAuthInfoKey)
au, ok := auth.(controllers.Auth)
if !ok || au.Username == "" {
ctx.Redirect(http.StatusFound, "/login")
ctx.Abort()
return
}
ctx.Set(controllers.DefaultAuthInfoKey, auth)
session.Options(sessions.Options{
Path: "/",
Domain: "localhost",
MaxAge: 7 * 24 * 60 * 60,
Secure: true,
HttpOnly: false,
SameSite: 0,
})
session.Set(controllers.DefaultAuthInfoKey, au)
session.Save()
}
}
func init() {
router = gin.Default()
router.MaxMultipartMemory = 8 << 20
router.Static("/static", "static")
router.LoadHTMLGlob("views/**/*")
gob.Register(controllers.Auth{})
store := cookie.NewStore([]byte("我是密钥"))
router.Use(sessions.Sessions("SESSION_ID", store))
router.GET("/login", controllers.LoginGet())
router.POST("/login", controllers.LoginPost())
router.Use(AuthRequired())
router.GET("/", controllers.Index())
}
main.go
package main
import (
"github.com/coolbit/gin_sample/routers"
)
func main() {
routers.GetRouter().Run(":80")
}
登录后才能使用的系统的登录逻辑,借助cookie,session
- 客户端发起
http://localhost/
请求。 - 请求须经过后端AuthRequired中间件鉴权。该中间件查看session中是否保存了请求携带的cookie对应的用户信息,若有。则登录成功;若没有,则重定向到
http://localhost/login
进行登录。 - GET方法请求
http://localhost/login
时只返回页面,不需鉴权逻辑。 - POST方法请求
http://localhost/login
时,不需鉴权逻辑。进行登录验证,并记录session,为当前context设置Key为"AUTH"的有效用户信息。方便该次请求链路使用。登录成功则重定向到http://localhost/
。