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/
相关推荐
天天向上10241 天前
在 Go 的 Gin Web 框架中,获取 HTTP 请求参数有多种方式
前端·golang·gin
迷途的小子6 天前
go-gin binding 标签详解
java·golang·gin
L Jiawen7 天前
【Go · Gin】基础知识
开发语言·golang·gin
ChineHe8 天前
Gin框架基础篇009_日志中间件详解
golang·web·gin
昵称为空C9 天前
go+gin 入门指南
go·gin
乐观主义现代人9 天前
gin 框架学习之路
学习·gin
golang学习记10 天前
[特殊字符] Go Gin 不停机重启指南:让服务在“洗澡搓背”中无缝升级
开发语言·golang·gin
ChineHe11 天前
Gin框架基础篇003_响应设置详解(状态码、头信息、多格式应答体)
后端·golang·gin
思成Codes12 天前
Gin 框架:*gin.Engine 主要方法
后端·golang·gin
思成Codes12 天前
Gin路由:构建高效RESTful API
golang·restful·xcode·gin