feat(bookmark): 初始化书签服务并配置路由与权限控制

新增书签服务主程序,使用 Gin 框架搭建 HTTP 服务器,并注册书签相关接口处理器。
配置 CORS 中间件以支持跨域请求。服务监听端口为 8081。

feat(user_np): 初始化用户权限服务并注册认证接口

新增用户权限服务主程序,使用 Gin 框架搭建 HTTP 服务器,并注册登录、注册及修改密码等接口处理器。
服务监听端口为 8082。

refactor(config): 重构 OpenAPI 配置文件结构并拆分模块

将原有合并的 OpenAPI 配置文件按功能模块拆分为 bookmark 和 user_np 两个独立目录,
分别管理各自的 server、client 及 API 定义文件,便于后续维护和扩展。

refactor(vfs): 调整虚拟文件系统 API 接口路径与参数定义

更新 VFS API 配置文件,修改部分接口路径及参数结构,
如将文件路径参数由 path 转为 query 参数,并优化响应结构体定义。
This commit is contained in:
zzy
2025-09-23 21:52:51 +08:00
parent 60d6628b0d
commit 1e81e603de
26 changed files with 1832 additions and 1685 deletions

100
internal/models/user_np.go Normal file
View File

@ -0,0 +1,100 @@
// internal/models/user_np.go
package models
import (
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// UserNP 用户名密码认证模型
type UserNP struct {
ID int64 `json:"id" gorm:"primaryKey"`
Username string `json:"username" gorm:"not null;index;size:255;unique"`
Password string `json:"password" gorm:"not null;size:255"`
Email *string `json:"email" gorm:"type:text;unique"`
Token *string `json:"token" gorm:"type:text"`
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
}
// JWTSecret JWT签名密钥在实际应用中应该从环境变量或配置文件中读取
var JWTSecret = []byte("your-secret-key-change-in-production")
// SimpleClaims 简单的JWT声明结构体
type SimpleClaims struct {
Username string `json:"username"`
jwt.RegisteredClaims
}
// HashPassword 对密码进行哈希处理
func (u *UserNP) HashPassword(password string) error {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
if err != nil {
return err
}
u.Password = string(bytes)
return nil
}
// CheckPassword 验证密码
func (u *UserNP) CheckPassword(providedPassword string) bool {
err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(providedPassword))
return err == nil
}
// GenerateSimpleJWT 生成简单的JWT Token
func (u *UserNP) GenerateSimpleJWT() (string, error) {
expirationTime := time.Now().Add(24 * time.Hour)
claims := &SimpleClaims{
Username: u.Username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
Issuer: "zzyxyz_user_np_api",
Subject: u.Username,
ID: string(rune(u.ID)), // 将用户ID作为JWT ID
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(JWTSecret)
if err != nil {
return "", err
}
return tokenString, nil
}
// CheckSimpleJWT 验证JWT Token
func CheckSimpleJWT(tokenString string) (string, error) {
claims := &SimpleClaims{}
// 解析token
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return JWTSecret, nil
})
if err != nil {
// 检查是否是token过期错误
if errors.Is(err, jwt.ErrTokenExpired) {
return "", errors.New("token已过期")
}
return "", errors.New("无效的token")
}
// 验证token有效性
if !token.Valid {
return "", errors.New("无效的token")
}
// 返回用户名
return claims.Username, nil
}