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

206 lines
6.4 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"
)
// UpdatePasswordRequest 更新密码请求参数结构
type UpdatePasswordRequest struct {
UserID string `json:"user_id" binding:"required"`
OldPassword string `json:"old_password" binding:"required"`
NewPassword string `json:"new_password" binding:"required,min=6"`
}
// UpdatePasswordResponse 更新密码响应结构
type UpdatePasswordResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
}
var db *sql.DB
func main() {
// 初始化日志输出格式
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
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,
)
var err error
db, err = sql.Open("postgres", connStr)
if err != nil {
log.Panicf("无法连接数据库: %v", err)
}
defer db.Close()
log.Println("数据库连接对象创建成功")
// 验证数据库连接
if err := db.Ping(); err != nil {
log.Panicf("数据库连接失败: %v", err)
}
log.Println("数据库连接验证成功")
// 更新密码接口
r.POST("/user/update/password", updatePasswordHandler)
log.Println("注册更新密码接口: POST /user/update/password")
// 启动服务监听80端口
log.Println("服务启动在80端口")
if err := r.Run(":80"); err != nil {
log.Panicf("服务启动失败: %v", err)
}
}
// updatePasswordHandler 处理密码更新逻辑
func updatePasswordHandler(c *gin.Context) {
requestID := c.Request.Header.Get("X-Request-ID")
if requestID == "" {
requestID = fmt.Sprintf("req-%d", gin.Mode())
}
log.Printf("[%s] 收到更新密码请求 from %s", requestID, c.ClientIP())
var req UpdatePasswordRequest
// 绑定并验证请求参数
if err := c.ShouldBindJSON(&req); err != nil {
log.Printf("[%s] 请求参数绑定失败: %v", requestID, err)
c.JSON(http.StatusBadRequest, UpdatePasswordResponse{
Success: false,
Message: "请求参数错误: " + err.Error(),
})
return
}
log.Printf("[%s] 请求参数验证通过, 用户ID: %s", requestID, req.UserID)
// 1. 检查新旧密码是否一致
if req.OldPassword == req.NewPassword {
log.Printf("[%s] 新密码与旧密码相同, 用户ID: %s", requestID, req.UserID)
c.JSON(http.StatusOK, UpdatePasswordResponse{
Success: false,
Message: "新密码不能与旧密码相同",
})
return
}
// 2. 对旧密码进行加密处理
log.Printf("[%s] 开始对旧密码进行加密, 用户ID: %s", requestID, req.UserID)
hashedOldPassword, err := bcrypt.GenerateFromPassword([]byte(req.OldPassword), bcrypt.DefaultCost)
if err != nil {
log.Printf("[%s] 旧密码加密失败: %v, 用户ID: %s", requestID, err, req.UserID)
c.JSON(http.StatusInternalServerError, UpdatePasswordResponse{
Success: false,
Message: "旧密码加密失败: " + err.Error(),
})
return
}
log.Printf("[%s] 旧密码加密完成, 用户ID: %s", requestID, req.UserID)
// 3. 使用加密后的旧密码查询并验证按user_id匹配
var count int
query := `
SELECT COUNT(*) FROM user_password
WHERE user_id = $1 AND password = $2
`
log.Printf("[%s] 执行旧密码验证查询, SQL: %s, 参数: [%s, ****]", requestID, query, req.UserID)
err = db.QueryRow(query, req.UserID, string(hashedOldPassword)).Scan(&count)
if err != nil {
log.Printf("[%s] 旧密码验证查询失败: %v, 用户ID: %s", requestID, err, req.UserID)
c.JSON(http.StatusInternalServerError, UpdatePasswordResponse{
Success: false,
Message: "验证旧密码失败: " + err.Error(),
})
return
}
// 验证失败处理
if count == 0 {
log.Printf("[%s] 旧密码验证失败, 用户ID: %s", requestID, req.UserID)
c.JSON(http.StatusOK, UpdatePasswordResponse{
Success: false,
Message: "旧密码不正确",
})
return
}
log.Printf("[%s] 旧密码验证成功, 用户ID: %s", requestID, req.UserID)
// 4. 对新密码进行加密处理
log.Printf("[%s] 开始对新密码进行加密, 用户ID: %s", requestID, req.UserID)
hashedNewPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
log.Printf("[%s] 新密码加密失败: %v, 用户ID: %s", requestID, err, req.UserID)
c.JSON(http.StatusInternalServerError, UpdatePasswordResponse{
Success: false,
Message: "新密码加密失败: " + err.Error(),
})
return
}
log.Printf("[%s] 新密码加密完成, 用户ID: %s", requestID, req.UserID)
// 5. 更新密码表中的密码按user_id匹配
updateQuery := `
UPDATE user_password
SET password = $1
WHERE user_id = $2
`
log.Printf("[%s] 执行密码更新, SQL: %s, 参数: [****, %s]", requestID, updateQuery, req.UserID)
result, err := db.Exec(updateQuery, string(hashedNewPassword), req.UserID)
if err != nil {
log.Printf("[%s] 密码更新执行失败: %v, 用户ID: %s", requestID, err, req.UserID)
c.JSON(http.StatusInternalServerError, UpdatePasswordResponse{
Success: false,
Message: "更新密码失败: " + err.Error(),
})
return
}
// 6. 检查更新结果
rowsAffected, err := result.RowsAffected()
if err != nil {
log.Printf("[%s] 获取更新行数失败: %v, 用户ID: %s", requestID, err, req.UserID)
c.JSON(http.StatusInternalServerError, UpdatePasswordResponse{
Success: false,
Message: "检查更新结果失败: " + err.Error(),
})
return
}
log.Printf("[%s] 密码更新影响行数: %d, 用户ID: %s", requestID, rowsAffected, req.UserID)
if rowsAffected == 0 {
log.Printf("[%s] 未找到用户或密码未变化, 用户ID: %s", requestID, req.UserID)
c.JSON(http.StatusOK, UpdatePasswordResponse{
Success: false,
Message: "未找到用户或密码未发生变化",
})
return
}
// 7. 更新成功
log.Printf("[%s] 密码更新成功, 用户ID: %s", requestID, req.UserID)
c.JSON(http.StatusOK, UpdatePasswordResponse{
Success: true,
Message: "密码更新成功",
})
}