feat: 新增 GET /api/v1/profile 用户信息查询接口,支持前端凭据查询当前用户

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 14:00:35 +08:00
parent aab8e47d3e
commit 83e94d9e97
3 changed files with 104 additions and 2 deletions
@@ -9,6 +9,8 @@ import (
"strings"
"time"
"github.com/yourname/cyrene-ai/gateway/internal/middleware"
"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
"golang.org/x/crypto/bcrypt"
@@ -91,7 +93,7 @@ func (h *AuthHandler) Register(c *gin.Context) {
}
// 存入 users 表
_, err = store.CreateUser(h.db, req.Username, string(passwordHash), false)
_, err = store.CreateUser(h.db, req.Username, req.Nickname, string(passwordHash), false)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "注册失败: " + err.Error()})
return
@@ -143,6 +145,7 @@ func (h *AuthHandler) Login(c *gin.Context) {
}
var userID string
var nickname string
// 尝试从 users 表查询用户
authenticated, err := h.verifyUserPassword(req.Username, req.Password)
@@ -158,6 +161,12 @@ func (h *AuthHandler) Login(c *gin.Context) {
} else {
userID = "user_" + req.Username
}
// 获取用户昵称
if h.db != nil {
if u, err := store.GetUserByUsername(h.db, req.Username); err == nil && u != nil {
nickname = u.Nickname
}
}
} else if req.Username == h.cfg.AdminUsername && h.db != nil {
// 管理员用户尚未迁移到 users 表,尝试用配置中的密码验证
if req.Password != h.cfg.AdminPassword {
@@ -169,13 +178,14 @@ func (h *AuthHandler) Login(c *gin.Context) {
if err != nil {
logger.Printf("⚠ 迁移管理员密码哈希失败: %v", err)
} else {
if _, err := store.CreateUser(h.db, req.Username, string(passwordHash), true); err != nil {
if _, err := store.CreateUser(h.db, req.Username, "管理员", string(passwordHash), true); err != nil {
logger.Printf("⚠ 迁移管理员到 users 表失败: %v", err)
} else {
logger.Println("✅ 管理员已迁移到 users 表")
}
}
userID = "admin"
nickname = "管理员"
} else if req.Username == h.cfg.AdminUsername {
// 数据库不可用时的回退:使用配置中的管理员密码
if req.Password != h.cfg.AdminPassword {
@@ -183,6 +193,7 @@ func (h *AuthHandler) Login(c *gin.Context) {
return
}
userID = "admin"
nickname = "管理员"
} else {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
@@ -203,6 +214,7 @@ func (h *AuthHandler) Login(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"nickname": nickname,
"token": token,
"refresh_token": refreshToken,
"expires": time.Now().Add(h.cfg.JWTExpiryHours).Unix(),
@@ -288,3 +300,63 @@ func (h *AuthHandler) RefreshToken(c *gin.Context) {
"expires": time.Now().Add(h.cfg.JWTExpiryHours).Unix(),
})
}
// GetProfile 查询当前登录用户信息
// GET /api/v1/profile
func (h *AuthHandler) GetProfile(c *gin.Context) {
userID := middleware.GetUserID(c)
isAdmin := middleware.GetIsAdmin(c)
var username string
var nickname string
if isAdmin {
username = "admin"
} else if strings.HasPrefix(userID, "user_") {
username = strings.TrimPrefix(userID, "user_")
} else {
username = userID
}
// 从数据库查询详细信息
if h.db != nil {
u, err := store.GetUserByUsername(h.db, username)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "服务器内部错误"})
return
}
if u != nil {
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"username": u.Username,
"nickname": u.Nickname,
"is_admin": u.IsAdmin,
"created_at": u.CreatedAt.UTC().Format(time.RFC3339),
})
return
}
// 用户不存在(可能 admin 未迁移或数据库问题)
if !isAdmin {
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
return
}
}
// 数据库不可用时的回退
if isAdmin {
nickname = h.cfg.AdminNickname
if nickname == "" {
nickname = "管理员"
}
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"username": username,
"nickname": nickname,
"is_admin": true,
"created_at": nil,
})
return
}
c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
}
@@ -71,6 +71,9 @@ func Setup(r *gin.Engine, hub *ws.Hub, cfg *config.Config, sessionStore *store.S
// Token刷新
protected.POST("/auth/refresh", authHandler.RefreshToken)
// 当前用户信息
protected.GET("/profile", authHandler.GetProfile)
// 会话管理
sessions := protected.Group("/sessions")
{
+27
View File
@@ -107,6 +107,33 @@ Auth: JWT(可接受已过期的 token,或在 body 中提供 refresh_token
---
### GET /profile — 查询当前用户
Auth: JWT。根据 token 返回当前登录用户的信息。
```json
// 响应 200
{
"user_id": "admin",
"username": "admin",
"nickname": "叶酱",
"is_admin": true,
"created_at": "2024-01-01T00:00:00Z"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `user_id` | string | 用户 IDadmin 为 `"admin"`,普通用户为 `"user_<username>"` |
| `username` | string | 用户名 |
| `nickname` | string | 显示昵称 |
| `is_admin` | bool | 是否管理员 |
| `created_at` | string | 注册时间 (RFC3339),数据库不可用时为 null |
错误: 401 `未提供认证令牌`, 404 `用户不存在`
---
## 2. WebSocket 实时通信
### GET /ws/chat — 建立连接