File size: 2,699 Bytes
3392510
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package api

import (
	"augment2api/config"
	"augment2api/pkg/logger"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

const (
	TokenKey = "login:token:"
)

// 生成随机会话令牌
func generateSessionToken() string {
	tokenUUID := uuid.New()
	return tokenUUID.String()
}

// LoginRequest 登录请求结构
type LoginRequest struct {
	Password string `json:"password"`
}

// LoginHandler 处理登录请求
func LoginHandler(c *gin.Context) {
	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "error",
			"error":  "无效的请求数据",
		})
		return
	}

	// 验证密码
	if req.Password == config.AppConfig.AccessPwd {
		// 生成会话令牌
		token := generateSessionToken()

		// 将会话令牌保存到Redis,有效期24小时
		sessionKey := TokenKey + token
		err := config.RedisSet(sessionKey, "valid", 24*time.Hour)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"status": "error",
				"error":  "保存会话失败: " + err.Error(),
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"status": "success",
			"token":  token,
		})
		return
	}

	// 密码错误
	c.JSON(http.StatusUnauthorized, gin.H{
		"status": "error",
		"error":  "密码错误",
	})
}

// ValidateToken 验证Token
func ValidateToken(token string) bool {
	if token == "" {
		return false
	}

	// 检查Redis中是否存在该token
	tokenKey := TokenKey + token
	exists, err := config.RedisExists(tokenKey)
	if err != nil || !exists {
		return false
	}

	return true
}

// AuthTokenMiddleware 会话认证中间件
func AuthTokenMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 如果未设置访问密码,则不需要验证
		if config.AppConfig.AccessPwd == "" {
			c.Next()
			return
		}

		// 从查询参数或Cookie中获取会话令牌
		token := c.GetHeader("X-Auth-Token")
		if token == "" {
			token = c.Query("token")
		}
		if token == "" {
			token, _ = c.Cookie("auth_token")
		}

		// 验证会话令牌
		if !ValidateToken(token) {
			logger.Log.Info("无效的会话令牌:", token)
			c.Redirect(http.StatusFound, "/login?error=token_expired")
			c.Abort()
			return
		}

		c.Next()
	}
}

// LogoutHandler 处理登出请求
func LogoutHandler(c *gin.Context) {
	token := c.GetHeader("X-Auth-Token")
	if token != "" {
		// 从Redis中删除会话token
		tokenKey := TokenKey + token
		err := config.RedisDel(tokenKey)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"status": "error",
				"error":  "删除会话失败: " + err.Error(),
			})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"status": "success",
	})
}