2024-10-29 16:17:07 +08:00

138 lines
3.9 KiB
Go

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,
})
}