package handler import ( _ "embed" "errors" "github.com/loveuer/nf" "github.com/loveuer/nf/nft/log" "github.com/loveuer/nf/nft/resp" "gorm.io/gorm" "net/http" "time" "uauth/internal/store/cache" "uauth/internal/store/db" "uauth/internal/tool" "uauth/model" ) var ( //go:embed serve_login.html pageLogin string ) func LoginPage(c *nf.Ctx) error { type Req struct { ClientId string `query:"client_id" json:"client_id"` Scope string `query:"scope" json:"scope"` RedirectURI string `query:"redirect_uri" json:"redirect_uri"` State string `query:"state" json:"state"` ResponseType string `query:"response_type" json:"response_type"` } var ( err error req = new(Req) client = new(model.Client) ) if err = c.QueryParser(req); err != nil { return resp.Resp400(c, err.Error()) } if req.ClientId == "" || req.RedirectURI == "" { return resp.Resp400(c, req) } if err = db.Default.Session().Model(&model.Client{}). Where("client_id = ?", req.ClientId). Take(client). Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return c.Status(http.StatusForbidden).SendString("Client Not Registry") } log.Error("[S] model take client id = %s, err = %s", req.ClientId, err.Error()) return c.Status(http.StatusInternalServerError).SendString("Internal Server Error") } return c.RenderHTML("login", pageLogin, map[string]interface{}{ "client_id": req.ClientId, "redirect_uri": req.RedirectURI, "scope": req.Scope, "state": req.State, "response_type": req.ResponseType, "client_name": client.Name, "client_icon": client.Icon, }) } //go:embed serve_login_success.html var pageLoginSuccess string func LoginAction(c *nf.Ctx) error { type Req struct { Username string `form:"username"` Password string `form:"password"` ClientId string `form:"client_id"` RedirectURI string `form:"redirect_uri"` Scope string `form:"scope"` State string `form:"state"` ResponseType string `form:"response_type"` } var ( err error req = new(Req) op = new(model.User) token string ) if err = c.BodyParser(req); err != nil { log.Warn("[S] LoginAction: body parser err = %s", err.Error()) return c.Status(http.StatusBadRequest).SendString("Bad Request") } if req.Username == "" || req.Password == "" { return c.Status(http.StatusBadRequest).SendString("Bad Request: username, password is required") } if err = db.Default.Session().Model(&model.User{}). Where("username = ?", req.Username). Take(op).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { log.Warn("[S] LoginAction: username = %s not found", req.Username) return c.Status(http.StatusBadRequest).SendString("Bad Request") } log.Error("[S] LoginAction: model take username = %s, err = %s", req.Username, err.Error()) return c.Status(http.StatusInternalServerError).SendString("Internal Server Error") } // todo: 验证用户登录是否成功,等等 if !tool.ComparePassword(req.Password, op.Password) { log.Warn("[S] LoginAction: model take username = %s, password is invalid", req.Username) return c.Status(http.StatusBadRequest).SendString("Bad Request") } if token, err = op.JwtEncode(); err != nil { log.Error("[S] LoginAction: jwtEncode err = %s", err.Error()) return c.Status(http.StatusInternalServerError).SendString("Internal Server Error") } key := cache.Prefix + "token:" + token if err = cache.Client.SetEx(c.Context(), key, op, 24*time.Hour); err != nil { log.Error("[S] LoginAction: cache SetEx err = %s", err.Error()) return c.Status(http.StatusInternalServerError).SendString("Internal Server Error") } c.Writer.Header().Add("Set-Cookie", "access_token="+token) return c.RenderHTML("login_success", pageLoginSuccess, map[string]interface{}{ "client_id": req.ClientId, "redirect_uri": req.RedirectURI, "scope": req.Scope, "state": req.State, "response_type": req.ResponseType, }) }