291 lines
8.5 KiB
Go
291 lines
8.5 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"chat-agent-system/internal/auth"
|
|
)
|
|
|
|
// extractBearerToken 从 Authorization 请求头解析 Bearer Token
|
|
func extractBearerToken(r *http.Request) string {
|
|
authHeader := r.Header.Get("Authorization")
|
|
if strings.HasPrefix(authHeader, "Bearer ") {
|
|
return strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer "))
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// authenticateUser 鉴权中间件辅助方法
|
|
func (s *Server) authenticateUser(r *http.Request) (*auth.UserAccount, error) {
|
|
token := extractBearerToken(r)
|
|
if token == "" {
|
|
token = r.Header.Get("X-Session-Token")
|
|
}
|
|
return s.authSvc.GetUserByToken(r.Context(), token)
|
|
}
|
|
|
|
// handleAuthLogin 用户名密码登录
|
|
func (s *Server) handleAuthLogin(w http.ResponseWriter, r *http.Request) {
|
|
var req struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的 JSON 请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
session, err := s.authSvc.Login(r.Context(), req.Username, req.Password)
|
|
if err != nil {
|
|
errMsg := err.Error()
|
|
if strings.Contains(errMsg, "审核") {
|
|
http.Error(w, errMsg, http.StatusForbidden)
|
|
return
|
|
}
|
|
if strings.Contains(errMsg, "停用") {
|
|
http.Error(w, errMsg, http.StatusForbidden)
|
|
return
|
|
}
|
|
http.Error(w, errMsg, http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(session)
|
|
}
|
|
|
|
// handleAuthRegister 用户自主注册 (职位严格由系统固定为访客)
|
|
func (s *Server) handleAuthRegister(w http.ResponseWriter, r *http.Request) {
|
|
var req auth.RegisterRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的 JSON 请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
resp, err := s.authSvc.Register(r.Context(), req)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(resp)
|
|
}
|
|
|
|
// handleAuthLogout 注销登录
|
|
func (s *Server) handleAuthLogout(w http.ResponseWriter, r *http.Request) {
|
|
token := extractBearerToken(r)
|
|
if token != "" {
|
|
s.authSvc.Logout(token)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
|
}
|
|
|
|
// handleAuthChangePassword 修改密码 (支持普通用户与首次强制改密)
|
|
func (s *Server) handleAuthChangePassword(w http.ResponseWriter, r *http.Request) {
|
|
user, err := s.authenticateUser(r)
|
|
if err != nil {
|
|
http.Error(w, "未登录或登录已过期", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
OldPassword string `json:"old_password"`
|
|
NewPassword string `json:"new_password"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的 JSON 请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := s.authSvc.ChangePassword(r.Context(), user.ID, req.OldPassword, req.NewPassword); err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
|
}
|
|
|
|
// handleAuthMe 获取当前登录用户身份
|
|
func (s *Server) handleAuthMe(w http.ResponseWriter, r *http.Request) {
|
|
user, err := s.authenticateUser(r)
|
|
if err != nil {
|
|
http.Error(w, "未登录或登录已过期", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
env := "dev"
|
|
if s.cfg != nil && s.cfg.Env != "" {
|
|
env = s.cfg.Env
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"user": user,
|
|
"must_change_password": user.MustChangePassword,
|
|
"env": env,
|
|
"allow_dev_switch": env == "dev",
|
|
})
|
|
}
|
|
|
|
// handleAdminUsers 管理员查询或新建用户
|
|
func (s *Server) handleAdminUsers(w http.ResponseWriter, r *http.Request) {
|
|
user, err := s.authenticateUser(r)
|
|
if err != nil || user.RoleID != "role-admin" {
|
|
http.Error(w, "权限不足,仅系统管理员可访问", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
if r.Method == http.MethodGet {
|
|
users, err := s.authSvc.ListUsers(r.Context())
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(map[string]any{"users": users})
|
|
return
|
|
}
|
|
|
|
if r.Method == http.MethodPost {
|
|
var req auth.CreateUserRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的 JSON 请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
created, err := s.authSvc.CreateUserByAdmin(r.Context(), req)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(created)
|
|
return
|
|
}
|
|
|
|
http.Error(w, "不支持的请求方法", http.StatusMethodNotAllowed)
|
|
}
|
|
|
|
// handleAdminUpdateRole 管理员为用户指定职位与角色
|
|
func (s *Server) handleAdminUpdateRole(w http.ResponseWriter, r *http.Request) {
|
|
user, err := s.authenticateUser(r)
|
|
if err != nil || user.RoleID != "role-admin" {
|
|
http.Error(w, "权限不足,仅系统管理员可访问", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
|
|
if len(parts) < 5 {
|
|
http.Error(w, "无效的用户路径参数", http.StatusBadRequest)
|
|
return
|
|
}
|
|
targetID, err := strconv.ParseInt(parts[3], 10, 64)
|
|
if err != nil {
|
|
http.Error(w, "无效的用户ID", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
RoleID string `json:"role_id"`
|
|
Position string `json:"position"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
updated, err := s.authSvc.UpdateUserRole(r.Context(), targetID, req.RoleID, req.Position)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(updated)
|
|
}
|
|
|
|
// handleAdminUpdateStatus 管理员审批通过/停用账号
|
|
func (s *Server) handleAdminUpdateStatus(w http.ResponseWriter, r *http.Request) {
|
|
user, err := s.authenticateUser(r)
|
|
if err != nil || user.RoleID != "role-admin" {
|
|
http.Error(w, "权限不足,仅系统管理员可访问", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
|
|
if len(parts) < 5 {
|
|
http.Error(w, "无效的用户路径参数", http.StatusBadRequest)
|
|
return
|
|
}
|
|
targetID, err := strconv.ParseInt(parts[3], 10, 64)
|
|
if err != nil {
|
|
http.Error(w, "无效的用户ID", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Status auth.AccountStatus `json:"status"`
|
|
RoleID string `json:"role_id,omitempty"`
|
|
Position string `json:"position,omitempty"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.RoleID != "" {
|
|
_, _ = s.authSvc.UpdateUserRole(r.Context(), targetID, req.RoleID, req.Position)
|
|
}
|
|
|
|
updated, err := s.authSvc.UpdateUserStatus(r.Context(), targetID, req.Status)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(updated)
|
|
}
|
|
|
|
// handleAdminConfig 获取或更新系统准入配置
|
|
func (s *Server) handleAdminConfig(w http.ResponseWriter, r *http.Request) {
|
|
user, err := s.authenticateUser(r)
|
|
if err != nil || user.RoleID != "role-admin" {
|
|
http.Error(w, "权限不足,仅系统管理员可访问", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
if r.Method == http.MethodGet {
|
|
cfg, err := s.authSvc.GetConfig(r.Context())
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(cfg)
|
|
return
|
|
}
|
|
|
|
if r.Method == http.MethodPut || r.Method == http.MethodPost {
|
|
var req auth.SystemAuthConfig
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "无效的请求体", http.StatusBadRequest)
|
|
return
|
|
}
|
|
if err := s.authSvc.UpdateConfig(r.Context(), req); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
_ = json.NewEncoder(w).Encode(req)
|
|
return
|
|
}
|
|
|
|
http.Error(w, "不支持的方法", http.StatusMethodNotAllowed)
|
|
}
|