package handler import ( "fmt" "net/http" "regexp" "gitea.starryskymeow.cn/B309/datamarket/internal/service" "github.com/go-chi/jwtauth/v5" "github.com/go-chi/render" ) type LoginRequest struct { Username string `json:"username"` Password string `json:"password"` } const usernameExpr = `^\S{3,32}$` const passwordExpr = `^\S{8,64}$` func (req *LoginRequest) Bind(_ *http.Request) error { // username if ok, _ := regexp.MatchString(usernameExpr, req.Username); !ok { return fmt.Errorf("invalid username, must match %q", usernameExpr) } // password if ok, _ := regexp.MatchString(passwordExpr, req.Password); !ok { return fmt.Errorf("invalid password, must match %q", passwordExpr) } return nil } // LoginHandler POST /api/auth/login func LoginHandler(auth service.AuthService) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { req := &LoginRequest{} if err := render.Bind(r, req); err != nil { w.WriteHeader(http.StatusBadRequest) renderServiceError(w, r, err) return } user, err := auth.VerifyUser(r.Context(), service.VerifyUserInput{ Username: req.Username, Password: req.Password, }) if err != nil { renderServiceError(w, r, err) return } http.SetCookie(w, &http.Cookie{ Name: "jwt", Value: user.Token, Path: "/", HttpOnly: true, Secure: true, MaxAge: 60 * 60 * 24, // 1d SameSite: http.SameSiteLaxMode, }) renderSuccess(w, r, http.StatusAccepted, "登录成功", user) } } func MeHandler(auth service.AuthService) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, claims, err := jwtauth.FromContext(r.Context()) if err != nil { renderServiceError(w, r, err) } renderSuccess(w, r, http.StatusOK, "logged in", claims) } }