gin实现登录逻辑,包含cookie,session

users/login.html

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

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

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() //TODO 必须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

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{             // 必须Save后才生效
			Path:     "/",
			Domain:   "localhost",
			MaxAge:   7 * 24 * 60 * 60, // 7天
			Secure:   true,
			HttpOnly: false,
			SameSite: 0,
		})

		session.Set(controllers.DefaultAuthInfoKey, au)
		session.Save() //"已刷新session"
	}
}

func init() {
	router = gin.Default()
	// Set a lower memory limit for multipart forms (default is 32 MiB)
	router.MaxMultipartMemory = 8 << 20 // 8 MiB
	router.Static("/static", "static")
	router.LoadHTMLGlob("views/**/*")
	
	gob.Register(controllers.Auth{}) // TODO 这个必须有,没有就写不了cookie
	
	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

go 复制代码
package main

import (
	"github.com/coolbit/gin_sample/routers"
)

func main() {
	routers.GetRouter().Run(":80")
}

登录后才能使用的系统的登录逻辑,借助cookie,session

  1. 客户端发起http://localhost/请求。
  2. 请求须经过后端AuthRequired中间件鉴权。该中间件查看session中是否保存了请求携带的cookie对应的用户信息,若有。则登录成功;若没有,则重定向到http://localhost/login进行登录。
  3. GET方法请求http://localhost/login时只返回页面,不需鉴权逻辑。
  4. POST方法请求http://localhost/login时,不需鉴权逻辑。进行登录验证,并记录session,为当前context设置Key为"AUTH"的有效用户信息。方便该次请求链路使用。登录成功则重定向到http://localhost/
相关推荐
RationalDysaniaer14 小时前
Gin入门笔记
笔记·gin
千年死缓14 小时前
gin中间件
中间件·gin
codists5 天前
《使用Gin框架构建分布式应用》阅读笔记:p393-p437
golang·gin·编程人
景天科技苑5 天前
【Golang】Gin框架中如何使用JWT来实现登录认证
开发语言·golang·gin·jwt·登录认证·go jwt
产幻少年6 天前
gin框架可以构建微服务吗?
微服务·gin
get2007 天前
golang gin ShouldBind的介绍和使用
开发语言·golang·gin
codists8 天前
《使用Gin框架构建分布式应用》阅读笔记:p272-p306
后端·go·gin
codists8 天前
《使用Gin框架构建分布式应用》阅读笔记:p212-p233
笔记·golang·gin·编程人·codists·gin框架
knoci8 天前
【Go】-基于Gin框架的博客项目
后端·学习·golang·gin
codists9 天前
《使用Gin框架构建分布式应用》阅读笔记:p251-p271
golang·gin·编程人