auth_middleware.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package utils
  2. import (
  3. "fmt"
  4. "github.com/beego/beego/v2/server/web/context"
  5. )
  6. // AuthMiddleware Token认证中间件
  7. func AuthMiddleware(ctx *context.Context) {
  8. // ============ 最优先:立即打印,证明中间件被调用 ============
  9. fmt.Printf("\n\n🚀🚀🚀🚀🚀 [AUTH中间件] 开始执行!\n")
  10. fmt.Printf(" 请求方法: %s\n", ctx.Request.Method)
  11. fmt.Printf(" 请求路径: %s\n", ctx.Request.URL.Path)
  12. fmt.Printf(" 完整URL: %s\n", ctx.Request.URL.String())
  13. // 添加一个 defer 来捕获任何 panic
  14. defer func() {
  15. if r := recover(); r != nil {
  16. fmt.Printf("❌❌❌ [中间件] 发生panic: %v\n", r)
  17. }
  18. }()
  19. // 跳过某些不需要认证的路由
  20. skipPaths := []string{
  21. "/stream-test",
  22. "/simple-stream-test",
  23. "/stream-chat-with-db-test",
  24. "/assets/",
  25. "/static/",
  26. "/src/",
  27. "/apiv1/oss/parse", // OSS代理解析接口,用于图片/文件资源访问,不需要token认证
  28. "/apiv1/auth/local_login", // 本地登录接口,不需要token认证
  29. }
  30. // 特殊处理:精确匹配根路径 "/"
  31. if ctx.Request.URL.Path == "/" {
  32. fmt.Printf("⏭️ [中间件] 跳过路径: / (根路径)\n\n")
  33. return
  34. }
  35. // 检查其他跳过路径
  36. for _, path := range skipPaths {
  37. // 精确匹配或前缀匹配(对于目录路径)
  38. if ctx.Request.URL.Path == path || (len(ctx.Request.URL.Path) > len(path) && ctx.Request.URL.Path[:len(path)] == path) {
  39. fmt.Printf("⏭️ [中间件] 跳过路径: %s (匹配规则: %s)\n\n", ctx.Request.URL.Path, path)
  40. return
  41. }
  42. }
  43. // 对于API请求,验证token
  44. if len(ctx.Request.URL.Path) >= 6 && ctx.Request.URL.Path[:6] == "/apiv1" {
  45. // 打印所有请求头,帮助调试
  46. fmt.Printf("\n========== Token认证中间件 ==========\n")
  47. fmt.Printf("📍 请求路径: %s\n", ctx.Request.URL.Path)
  48. fmt.Printf("📋 所有请求头:\n")
  49. for key, values := range ctx.Request.Header {
  50. fmt.Printf(" %s: %v\n", key, values)
  51. }
  52. // 获取token - 添加详细的调试信息
  53. fmt.Printf("\n🔍 开始提取Token:\n")
  54. token1 := ctx.Input.Header("token")
  55. fmt.Printf(" 尝试 'token': %s (长度: %d)\n", token1, len(token1))
  56. token2 := ctx.Input.Header("Token")
  57. fmt.Printf(" 尝试 'Token': %s (长度: %d)\n", token2, len(token2))
  58. token3 := ctx.Input.Header("Authorization")
  59. fmt.Printf(" 尝试 'Authorization': %s (长度: %d)\n", token3, len(token3))
  60. // 确定最终使用的token
  61. token := token1
  62. if token == "" {
  63. token = token2
  64. }
  65. if token == "" {
  66. token = token3
  67. // 如果是Bearer token格式,去掉"Bearer "前缀
  68. if len(token) > 7 && token[:7] == "Bearer " {
  69. oldToken := token
  70. token = token[7:]
  71. fmt.Printf(" 去除Bearer前缀: %s -> %s\n", oldToken[:20]+"...", token[:20]+"...")
  72. }
  73. }
  74. fmt.Printf("\n🔑 最终提取到的Token: %s (长度: %d)\n", token, len(token))
  75. // 如果没有token,返回401
  76. if token == "" {
  77. fmt.Printf("❌❌❌ Token为空,拒绝请求\n")
  78. fmt.Printf("❌ 原因:请求头中没有找到 token、Token 或 Authorization 字段\n")
  79. fmt.Printf("=====================================\n\n")
  80. ctx.Output.SetStatus(401)
  81. ctx.Output.JSON(map[string]interface{}{
  82. "statusCode": 401,
  83. "msg": "未提供认证token,请在请求头中添加 token 字段",
  84. }, false, false)
  85. return
  86. }
  87. // ========== 优先验证本地token ==========
  88. fmt.Printf("\n🔍 [中间件] 尝试验证本地token...\n")
  89. localClaims, err := VerifyLocalToken(token)
  90. if err == nil && localClaims != nil {
  91. // 本地token验证成功
  92. fmt.Printf("✅ [中间件] 本地Token验证成功\n")
  93. fmt.Printf(" - UserID: %d\n", localClaims.UserID)
  94. fmt.Printf(" - Username: %s\n", localClaims.Username)
  95. fmt.Printf(" - Role: %s\n", localClaims.Role)
  96. // 转换为TokenUserInfo格式
  97. userInfo := ConvertLocalClaimsToTokenUserInfo(localClaims)
  98. // 存储到context
  99. fmt.Printf("\n💾 [中间件] 将本地用户信息存储到context中...\n")
  100. ctx.Input.SetData("userInfo", userInfo)
  101. fmt.Printf("=====================================\n\n")
  102. return
  103. }
  104. fmt.Printf("⚠️ [中间件] 本地token验证失败: %v, 尝试统一认证...\n", err)
  105. // ========== 统一认证token验证 ==========
  106. // 验证token
  107. userInfo, err := VerifyToken(token)
  108. if err != nil {
  109. fmt.Printf("❌❌❌ Token验证失败: %v\n", err)
  110. fmt.Printf("❌ Token内容: %s\n", token)
  111. fmt.Printf("❌ 请检查token是否正确或已过期\n")
  112. fmt.Printf("=====================================\n\n")
  113. ctx.Output.SetStatus(401)
  114. ctx.Output.JSON(map[string]interface{}{
  115. "statusCode": 401,
  116. "msg": fmt.Sprintf("token验证失败: %v", err),
  117. }, false, false)
  118. return
  119. }
  120. // 打印解析出的用户信息
  121. fmt.Printf("✅ Token验证成功,解析出的用户信息:\n")
  122. fmt.Printf(" - AccountID: %s\n", userInfo.AccountID)
  123. fmt.Printf(" - ID: %d\n", userInfo.ID)
  124. fmt.Printf(" - Name: %s\n", userInfo.Name)
  125. fmt.Printf(" - UserCode: %s\n", userInfo.UserCode)
  126. fmt.Printf(" - ContactNumber: %s\n", userInfo.ContactNumber)
  127. fmt.Printf(" - TokenType: %s\n", userInfo.TokenType)
  128. // 将用户信息存储到context中,供后续handler使用
  129. fmt.Printf("\n💾 [中间件] 将用户信息存储到context中...\n")
  130. fmt.Printf(" 存储的指针地址: %p\n", userInfo)
  131. fmt.Printf(" 存储的值: %+v\n", userInfo)
  132. ctx.Input.SetData("userInfo", userInfo)
  133. // 验证是否存储成功
  134. storedData := ctx.Input.GetData("userInfo")
  135. fmt.Printf(" 验证存储: %T, 值=%+v\n", storedData, storedData)
  136. fmt.Printf("=====================================\n\n")
  137. } else {
  138. fmt.Printf("⏭️ [中间件] 非API路径,不需要token验证: %s\n\n", ctx.Request.URL.Path)
  139. }
  140. }