Files
zzyxyz_go_api/internal/bookmarks/user_np.go
zzy cf47ef66c3 feat(user_np): 更新用户认证接口路径与实现
- 修改登录接口路径为 /auth/user/{username}/login,并更新对应处理函数
- 修改注册接口路径为 /auth/user/{username},并更新对应处理函数
- 将修改密码接口从 PUT /auth/password 改为 PATCH /auth/user/{username}
- 新增删除用户接口 DELETE /auth/user/{username}
- 新增获取用户信息接口 GET /auth/user/{username}/info
- 更新请求体结构,移除冗余的 username 字段,使用路径参数传递用户名
- 实现 DeleteUser、UpdatePassword 等新接口逻辑
- 调整 OpenAPI 文档中各接口的 operationId 和参数定义
2025-09-27 16:25:37 +08:00

244 lines
6.2 KiB
Go

// internal/handlers/user_np.go
package bookmarks
import (
"context"
"fmt"
"net/http"
api "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/user_np_server"
client "git.zzyxyz.com/zzy/zzyxyz_go_api/gen/vfs_client"
"git.zzyxyz.com/zzy/zzyxyz_go_api/internal/bookmarks/models"
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type UserNPImpl struct {
db *gorm.DB
client *client.ClientWithResponses
vfsToken string
}
func NewUserNP(dbPath string) (*UserNPImpl, error) {
var err error
var db *gorm.DB
db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
if err != nil {
return nil, err
}
// 自动迁移表结构
err = db.AutoMigrate(&models.UserNP{})
if err != nil {
return nil, err
}
client, err := client.NewClientWithResponses("http://localhost:8080/api")
if err != nil {
return nil, err
}
return &UserNPImpl{
db: db,
client: client,
vfsToken: "random_token",
}, nil
}
func (u *UserNPImpl) RegisterVFSService(username, token string) (*string, error) {
ctx := context.Background()
reqs, err := u.client.CreateUserWithResponse(ctx, username, func(ctx context.Context, req *http.Request) error {
req.Header.Set("X-VFS-Token", token)
return nil
})
if err != nil {
return nil, err
}
if reqs.StatusCode() != http.StatusCreated {
return nil, fmt.Errorf("failed to register vfs service: %s", reqs.Status())
}
tokenHeader := reqs.HTTPResponse.Header.Get("X-VFS-Token")
if tokenHeader == "" {
return nil, fmt.Errorf("X-VFS-Token header is missing")
}
return &tokenHeader, nil
}
func (u *UserNPImpl) UnregisterVFSService(username, token string) error {
ctx := context.Background()
reqs, err := u.client.DeleteUserWithResponse(ctx, username, func(ctx context.Context, req *http.Request) error {
req.Header.Set("X-VFS-Token", token)
return nil
})
if err != nil {
return err
}
if reqs.StatusCode() == http.StatusNoContent {
return nil
}
if reqs.JSON404 != nil {
return fmt.Errorf("用户不存在 %s", reqs.JSON404.Message)
}
if reqs.JSON500 != nil {
return fmt.Errorf("服务器错误 %s", reqs.JSON500.Message)
}
return fmt.Errorf("未知错误")
}
// UserLogin implements server.ServerInterface.
func (u *UserNPImpl) UserLogin(c *gin.Context, username string) {
var req api.UserLoginJSONRequestBody
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 查找用户
var user models.UserNP
if err := u.db.Where("username = ?", username).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
// 验证密码
if !user.CheckPassword(req.Password) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
c.JSON(http.StatusOK, api.LoginResponse{
Token: user.Token,
UserId: &user.ID,
})
}
// UserRegister implements server.ServerInterface.
func (u *UserNPImpl) UserRegister(c *gin.Context, username string) {
var req api.UserRegisterJSONRequestBody
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 检查用户名是否已存在
var existingUser models.UserNP
if err := u.db.Where("username = ?", username).First(&existingUser).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"})
return
}
// 创建新用户
user := models.UserNP{
Username: username,
Email: req.Email,
}
// 加密密码
if err := user.HashPassword(req.Password); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码处理失败"})
return
}
// 保存到数据库
if err := u.db.Create(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "用户创建失败"})
}
if token, err := u.RegisterVFSService(username, u.vfsToken); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法生成访问令牌"})
u.db.Delete(&user)
} else {
user.Token = token
u.db.Save(&user)
}
c.JSON(http.StatusCreated, nil)
}
// DeleteUser implements server.ServerInterface.
func (u *UserNPImpl) DeleteUser(c *gin.Context, username string) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少访问令牌"})
return
}
// 查找用户
var user models.UserNP
if err := u.db.Where("username = ?", username).First(&user).Error; err != nil {
c.JSON(http.StatusNoContent, nil)
return
}
if user.Token == nil || *user.Token != authHeader {
c.JSON(http.StatusUnauthorized, gin.H{"error": "访问令牌错误"})
return
}
u.db.Delete(&user)
c.JSON(http.StatusNoContent, nil)
}
// UpdatePassword implements server.ServerInterface.
func (u *UserNPImpl) UpdatePassword(c *gin.Context, username string) {
// 获取Authorization头中的token
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少访问令牌"})
return
}
var req api.UpdatePasswordJSONRequestBody
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 查找用户
var user models.UserNP
if err := u.db.Where("username = ?", username).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户不存在"})
return
}
// 验证旧密码
if !user.CheckPassword(req.OldPassword) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "旧密码错误"})
return
}
// 加密新密码
if err := user.HashPassword(req.NewPassword); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码处理失败"})
return
}
// 保存到数据库
if err := u.db.Save(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "密码更新失败"})
return
}
c.JSON(http.StatusOK, nil)
}
// GetUserInfo implements server.ServerInterface.
func (u *UserNPImpl) GetUserInfo(c *gin.Context, username string) {
panic("unimplemented")
}
// SaveUserInfo implements server.ServerInterface.
func (u *UserNPImpl) SaveUserInfo(c *gin.Context, username string) {
panic("unimplemented")
}
// Make sure we conform to ServerInterface
var _ api.ServerInterface = (*UserNPImpl)(nil)