前言
- Redis建议只执行一些标记 短时间、轻量级的,并且Redis带有key过期的属性,执行一些登录失效、秒杀订单过期时间标记,Redis本不执行任何的业务逻辑。
Redis缓存以及JWT双重验证登录
- 导入redis包
go get github.com/go-redis/redis/v8
- 初始化Redis 新建 utlis/redis.go
package utils
import (
"context"
"docker-go-app/config"
"log"
"github.com/go-redis/redis/v8"
)
var (
RedisClient *redis.Client
Ctx = context.Background()
)
func InitRedis() {
RedisClient = redis.NewClient(&redis.Options{
Addr: config.GetRedisAddr(),
Password: "",
DB: config.GetRedisDB(),
})
}
func TestRedis() {
err := RedisClient.Ping(Ctx).Err()
if err != nil {
log.Fatalf("Redis连接失败: %v", err)
}
log.Println("Redis连接成功")
}
- main.go初始化方法
package main
import (
"docker-go-app/config"
"docker-go-app/middleware"
"docker-go-app/model"
"docker-go-app/routers"
"docker-go-app/utils"
"log"
"github.com/gin-gonic/gin"
)
func main() {
config.InitConfig()
utils.InitRedis()
utils.TestRedis()
r := gin.Default()
routers.InitRouter(r)
r.Run(":8080")
}
- user_controller.go 控制器登录成功之后,redis 缓存token
func (uc *UserController) Login(c *gin.Context) {
var loginForm types.LoginRequest
if err := c.ShouldBindJSON(&loginForm); err != nil {
utils.ParamError(c, "手机号和密码不能为空")
return
}
user, token, err := uc.UserService.Login(loginForm.Phone, loginForm.Password)
if err != nil {
if err.Error() == "用户不存在" {
utils.Fail(c, utils.ERROR_AUTH, "用户不存在")
} else if err.Error() == "密码错误" {
utils.Fail(c, utils.ERROR_AUTH, "密码错误")
} else {
utils.Fail(c, utils.ERROR_AUTH, "登录失败")
}
return
}
utils.RedisClient.Set(utils.Ctx, "token:"+token, user.ID, time.Hour*24)
response := types.LoginResponse{
Token: token,
User: struct {
ID uint `json:"id" example:"1"`
CreatedAt time.Time `json:"created_at" example:"2025-07-13T18:00:00Z"`
UpdatedAt time.Time `json:"updated_at" example:"2025-07-13T18:00:00Z"`
Username string `json:"username" example:"张三"`
Email string `json:"email" example:"zhangsan@example.com"`
Phone string `json:"phone" example:"13800138000"`
Status string `json:"status" example:"1"`
RealName string `json:"real_name" example:"张三"`
}{
ID: user.ID,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Status: user.Status,
RealName: user.RealName,
},
}
utils.Success(c, response)
}
- 路由分组 userRouter.go 里 ,设置哪些路由是需要认证效验
package routers
import (
"docker-go-app/controllers"
"docker-go-app/middleware"
"docker-go-app/services"
"github.com/gin-gonic/gin"
)
func InitUserRouter(r *gin.Engine) {
apiV1 := r.Group("/api/v1")
userService := &services.UserService{}
userController := &controllers.UserController{
UserService: userService,
}
public := apiV1.Group("/public")
{
public.POST("/login", userController.Login)
public.POST("/register", userController.Register)
}
protected := apiV1.Group("/user")
protected.Use(middleware.Auth())
{
}
}
- middleware/auth.go 在中间件里写入认证效验,满足则继续执行不满足则停止
package middleware
import (
"docker-go-app/utils"
"strings"
"github.com/gin-gonic/gin"
)
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
utils.AuthError(c)
c.Abort()
return
}
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
utils.AuthError(c)
c.Abort()
return
}
tokenString := parts[1]
_, err := utils.RedisClient.Get(utils.Ctx, "token:"+tokenString).Result()
if err != nil {
utils.AuthError(c)
c.Abort()
return
}
claims, err := utils.ParseToken(tokenString)
if err != nil {
if strings.Contains(err.Error(), "expired") {
utils.Fail(c, utils.ERROR_AUTH, "登录已过期,请重新登录")
} else {
utils.AuthError(c)
}
c.Abort()
return
}
c.Set("userID", claims.UserID)
c.Set("phone", claims.Phone)
c.Next()
}
}