Files
user_service/deploy/api/api_login/main.go
2025-10-09 18:19:57 +08:00

162 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
"golang.org/x/crypto/bcrypt"
)
// LoginRequest 登录请求参数结构
type LoginRequest struct {
Account string `json:"account" binding:"required"`
Password string `json:"password" binding:"required"`
}
// LoginResponse 登录响应结构
type LoginResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
Data struct {
UserID string `json:"user_id,omitempty"`
} `json:"data,omitempty"`
}
var db *sql.DB
func main() {
log.Println("开始初始化应用程序")
// 初始化Gin引擎
r := gin.Default()
log.Println("Gin引擎初始化完成")
// 从环境变量获取数据库配置
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbUser := os.Getenv("DB_USER")
dbPassword := os.Getenv("DB_PASSWORD")
dbName := os.Getenv("DB_NAME")
log.Printf("获取数据库配置: host=%s, port=%s, user=%s, dbname=%s", dbHost, dbPort, dbUser, dbName)
// 构建数据库连接字符串
connStr := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
dbHost, dbPort, dbUser, dbPassword, dbName,
)
log.Printf("数据库连接字符串构建完成: %s", connStr)
var err error
db, err = sql.Open("postgres", connStr)
if err != nil {
log.Fatalf("无法连接数据库: %v", err)
panic(fmt.Sprintf("无法连接数据库: %v", err))
}
defer db.Close()
log.Println("数据库连接对象创建成功")
// 验证数据库连接
if err := db.Ping(); err != nil {
log.Fatalf("数据库连接失败: %v", err)
panic(fmt.Sprintf("数据库连接失败: %v", err))
}
log.Println("数据库连接验证成功")
// 登录接口
r.POST("/user/login", loginHandler)
log.Println("登录接口注册完成: POST /user/login")
// 启动服务监听80端口
log.Println("服务启动在80端口")
r.Run(":80")
}
// loginHandler 处理登录逻辑
func loginHandler(c *gin.Context) {
reqID := c.Request.Header.Get("X-Request-ID")
if reqID == "" {
reqID = fmt.Sprintf("%d", gin.Mode()) // 简单生成一个请求标识
}
log.Printf("[%s] 收到登录请求 from %s", reqID, c.ClientIP())
var req LoginRequest
// 绑定并验证请求参数
if err := c.ShouldBindJSON(&req); err != nil {
log.Printf("[%s] 请求参数绑定失败: %v, 请求体: %+v", reqID, err, c.Request.Body)
c.JSON(http.StatusBadRequest, LoginResponse{
Success: false,
Message: "账号或密码不能为空",
})
return
}
log.Printf("[%s] 请求参数绑定成功: 账号=%s", reqID, req.Account)
// 1. 判断账号和密码是否为空(双重保险)
if req.Account == "" || req.Password == "" {
log.Printf("[%s] 账号或密码为空: 账号=%s", reqID, req.Account)
c.JSON(http.StatusBadRequest, LoginResponse{
Success: false,
Message: "账号或密码不能为空",
})
return
}
// 2. 查询账号对应的密码和用户ID
var storedPassword string
var userID string
query := `
SELECT password, user_id
FROM user_account_password_view
WHERE account = $1 AND deleted = false
`
log.Printf("[%s] 执行查询: %s, 参数: %s", reqID, query, req.Account)
err := db.QueryRow(query, req.Account).Scan(&storedPassword, &userID)
switch {
case err == sql.ErrNoRows:
// 账号不存在或已被删除
log.Printf("[%s] 账号不存在或已删除: %s", reqID, req.Account)
c.JSON(http.StatusOK, LoginResponse{
Success: false,
Message: "账号不存在",
})
return
case err != nil:
log.Printf("[%s] 查询账号信息失败: %v, 账号=%s", reqID, err, req.Account)
c.JSON(http.StatusInternalServerError, LoginResponse{
Success: false,
Message: "查询账号信息失败",
})
return
}
log.Printf("[%s] 查询账号信息成功: 账号=%s, userID=%s", reqID, req.Account, userID)
// 3. 验证密码使用bcrypt比较原始密码和存储的加密密码
err = bcrypt.CompareHashAndPassword([]byte(storedPassword), []byte(req.Password))
if err != nil {
// 密码不匹配
log.Printf("[%s] 密码验证失败: 账号=%s, 错误=%v", reqID, req.Account, err)
c.JSON(http.StatusOK, LoginResponse{
Success: false,
Message: "密码错误",
})
return
}
log.Printf("[%s] 密码验证成功: 账号=%s", reqID, req.Account)
// 4. 登录成功
log.Printf("[%s] 登录成功: 账号=%s, userID=%s", reqID, req.Account, userID)
c.JSON(http.StatusOK, LoginResponse{
Success: true,
Message: "登录成功",
Data: struct {
UserID string `json:"user_id,omitempty"`
}{
UserID: userID,
},
})
}