diff --git a/docker-compose.yml b/docker-compose.yml index 560c770..ae38ad6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,7 +32,7 @@ services: context: ./web dockerfile: backend/Dockerfile container_name: trade-web - env_file: ./web/backend/.env + # .env 已移除,环境变量直接写在此处 environment: - LISTEN_ADDR=:8080 - DATABASE_URL=postgres://trade:trade@postgres:5432/futures?sslmode=disable diff --git a/web/backend/.env.example b/web/backend/.env.example deleted file mode 100644 index 5bd622b..0000000 --- a/web/backend/.env.example +++ /dev/null @@ -1,8 +0,0 @@ -# 拷贝为 web/backend/.env 后填入真实值。.env 已被 .gitignore 排除。 -# 首次启动时,若 auth.db 中没有任何 admin 用户,会用下面这一对凭据创建管理员; -# 一旦 admin 已存在,这两个变量会被忽略,改它们不会改密码。 -ADMIN_USER=admin -ADMIN_PASS=changeme - -# JWT 签名密钥;生成方式:openssl rand -hex 32 -JWT_SECRET=replace-with-32-bytes-hex diff --git a/web/backend/internal/config/config.go b/web/backend/internal/config/config.go index bd76627..bc5a28d 100644 --- a/web/backend/internal/config/config.go +++ b/web/backend/internal/config/config.go @@ -3,15 +3,13 @@ package config import ( "fmt" "os" - "strings" ) type Config struct { - ListenAddr string - DatabaseURL string - AuthDBPath string - JWTSecret []byte - TushareAPIURL string + ListenAddr string + DatabaseURL string + AuthDBPath string + TushareAPIURL string } func Load() (*Config, error) { @@ -24,11 +22,6 @@ func Load() (*Config, error) { if cfg.DatabaseURL == "" { return nil, fmt.Errorf("DATABASE_URL 环境变量未设置") } - secret := strings.TrimSpace(os.Getenv("JWT_SECRET")) - if len(secret) < 16 { - return nil, fmt.Errorf("JWT_SECRET 必须至少 16 个字符 (建议 openssl rand -hex 32)") - } - cfg.JWTSecret = []byte(secret) return cfg, nil } diff --git a/web/backend/internal/handlers/auth.go b/web/backend/internal/handlers/auth.go index aef4b62..a9b7490 100644 --- a/web/backend/internal/handlers/auth.go +++ b/web/backend/internal/handlers/auth.go @@ -54,13 +54,9 @@ func (d *Deps) Login(w http.ResponseWriter, r *http.Request) { writeErr(w, http.StatusUnauthorized, "用户名或密码错误") return } - token, _, err := d.JWT.Issue(u.ID, u.Username, u.Role) - if err != nil { - writeErr(w, http.StatusInternalServerError, "issue token failed") - return - } + // 暂时不用 JWT,返回固定 token writeJSON(w, http.StatusOK, loginResp{ - Token: token, + Token: "noop", User: publicUserView{ ID: u.ID, Username: u.Username, diff --git a/web/backend/internal/handlers/deps.go b/web/backend/internal/handlers/deps.go index 2ed8e17..afaff03 100644 --- a/web/backend/internal/handlers/deps.go +++ b/web/backend/internal/handlers/deps.go @@ -5,16 +5,14 @@ import ( "log" "net/http" - "trade/web/internal/auth" "trade/web/internal/store" ) // Deps 是所有 handler 需要的运行时依赖,在 router 装配时一次性注入。 type Deps struct { - Auth *store.AuthStore - Futures *store.FuturesStore - JWT *auth.Manager - TushareURL string + Auth *store.AuthStore + Futures *store.FuturesStore + TushareURL string } func writeJSON(w http.ResponseWriter, status int, body any) { diff --git a/web/backend/internal/middleware/auth.go b/web/backend/internal/middleware/auth.go index 9598848..365025c 100644 --- a/web/backend/internal/middleware/auth.go +++ b/web/backend/internal/middleware/auth.go @@ -3,9 +3,7 @@ package middleware import ( "context" "net/http" - "strings" - "trade/web/internal/auth" "trade/web/internal/store" ) @@ -24,32 +22,14 @@ func FromContext(ctx context.Context) (CtxUser, bool) { return u, ok } -// RequireUser 校验 Authorization Bearer JWT,通过后把 CtxUser 写入 context。 -// 同时校验数据库里的 disabled 状态,被禁用的账户即使持有 token 也会被拒。 -func RequireUser(mgr *auth.Manager, s *store.AuthStore) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tok := bearer(r) - if tok == "" { - writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "missing token"}) - return - } - claims, err := mgr.Parse(tok) - if err != nil { - writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "invalid token"}) - return - } - u, err := s.GetByID(claims.UserID) - if err != nil || u.Disabled { - writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "account disabled or removed"}) - return - } - ctx := context.WithValue(r.Context(), userKey, CtxUser{ - ID: u.ID, Username: u.Username, Role: u.Role, - }) - next.ServeHTTP(w, r.WithContext(ctx)) +// RequireUser 不再校验 JWT,直接注入默认管理员用户,所有请求放行。 +func RequireUser(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), userKey, CtxUser{ + ID: 1, Username: "admin", Role: store.RoleAdmin, }) - } + next.ServeHTTP(w, r.WithContext(ctx)) + }) } func RequireAdmin(next http.Handler) http.Handler { @@ -62,12 +42,3 @@ func RequireAdmin(next http.Handler) http.Handler { next.ServeHTTP(w, r) }) } - -func bearer(r *http.Request) string { - h := r.Header.Get("Authorization") - const p = "Bearer " - if strings.HasPrefix(h, p) { - return strings.TrimSpace(h[len(p):]) - } - return "" -} diff --git a/web/backend/internal/router/router.go b/web/backend/internal/router/router.go index acd35ba..e109c27 100644 --- a/web/backend/internal/router/router.go +++ b/web/backend/internal/router/router.go @@ -7,13 +7,11 @@ import ( "github.com/go-chi/chi/v5" - "trade/web/internal/auth" "trade/web/internal/handlers" mw "trade/web/internal/middleware" - "trade/web/internal/store" ) -func New(d *handlers.Deps, mgr *auth.Manager, authStore *store.AuthStore, dist fs.FS) http.Handler { +func New(d *handlers.Deps, dist fs.FS) http.Handler { r := chi.NewRouter() r.Use(mw.Recover) r.Use(mw.Logger) @@ -22,7 +20,7 @@ func New(d *handlers.Deps, mgr *auth.Manager, authStore *store.AuthStore, dist f r.Post("/login", d.Login) r.Group(func(r chi.Router) { - r.Use(mw.RequireUser(mgr, authStore)) + r.Use(mw.RequireUser) r.Post("/logout", d.Logout) r.Get("/me", d.Me) diff --git a/web/backend/main.go b/web/backend/main.go index 5ae77db..e1f9379 100644 --- a/web/backend/main.go +++ b/web/backend/main.go @@ -40,8 +40,7 @@ func main() { log.Fatalf("bootstrap: %v", err) } - mgr := auth.NewManager(cfg.JWTSecret) - deps := &handlers.Deps{Auth: authDB, Futures: futures, JWT: mgr, TushareURL: cfg.TushareAPIURL} + deps := &handlers.Deps{Auth: authDB, Futures: futures, TushareURL: cfg.TushareAPIURL} dist, err := fs.Sub(distFS, "dist") if err != nil { @@ -50,7 +49,7 @@ func main() { srv := &http.Server{ Addr: cfg.ListenAddr, - Handler: router.New(deps, mgr, authDB, dist), + Handler: router.New(deps, dist), ReadHeaderTimeout: 10 * time.Second, }