74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
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)
|
|
}
|
|
}
|