uauth/internal/serve/handler/authorize.go

125 lines
3.5 KiB
Go
Raw Normal View History

2024-10-23 17:46:15 +08:00
package handler
import (
_ "embed"
"errors"
"github.com/google/uuid"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
"github.com/loveuer/nf/nft/resp"
"gorm.io/gorm"
"net/http"
"net/url"
"time"
"uauth/model"
"uauth/pkg/cache"
"uauth/pkg/store"
"uauth/tool"
2024-10-23 17:46:15 +08:00
)
var (
//go:embed serve_authorize.html
pageAuthorize string
)
func Authorize(c *nf.Ctx) error {
type Req struct {
ClientId string `query:"client_id"`
ResponseType string `query:"response_type"`
RedirectURI string `query:"redirect_uri"`
Scope string `query:"scope"`
State string `query:"state"`
}
var (
ok bool
op *model.User
req = new(Req)
err error
client = &model.Client{}
authRecord = &model.AuthorizationRecord{}
uri *url.URL
)
if err = c.QueryParser(req); err != nil {
log.Error("[S] query parser err = %s", err.Error())
return c.Status(http.StatusBadRequest).SendString("Invalid request")
}
if req.ResponseType != "code" {
log.Warn("[S] response type = %s", req.ResponseType)
return c.Status(http.StatusBadRequest).SendString("Invalid request")
}
// 如果未登录,则跳转到登录界面
if op, ok = c.Locals("user").(*model.User); !ok {
log.Info("[S] op not logined, redirect to login page")
return c.Redirect("/oauth/v2/login?"+c.Request.URL.Query().Encode(), http.StatusFound)
}
log.Info("[S] Authorize: username = %s, client_id = %s", op.Username, req.ClientId)
if err = store.Default.Session(tool.TimeoutCtx(c.Context(), 3)).
Where("client_id", req.ClientId).Take(client).Error; err != nil {
2024-10-23 17:46:15 +08:00
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.Status(http.StatusBadRequest).SendString("Bad Request: invalid client_id")
}
log.Error("[Authorize]: db take clients err = %s", err.Error())
return c.Status(http.StatusInternalServerError).SendString("Internal Server Error")
}
if err = store.Default.Session(tool.TimeoutCtx(c.Context(), 3)).
Model(&model.AuthorizationRecord{}).
2024-10-23 17:46:15 +08:00
Where("user_id", op.Id).
Where("client_id", client.Id).
Take(authRecord).
Error; err != nil {
// 用户第一次对该 client 进行授权
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.RenderHTML("authorize", pageAuthorize, map[string]any{
"user": map[string]any{
"username": op.Username,
"avatar": "https://picsum.photos/200",
},
"client_id": req.ClientId,
"redirect_uri": req.RedirectURI,
"scope": req.Scope,
"state": req.State,
})
}
log.Error("[Authorize]: db take authorization_records err = %s", err.Error())
return resp.Resp500(c, err)
}
// 当用户已经授权过时
// 生成授权码并缓存授权码
log.Debug("[Authorize]: username = %s already approved %s", op.Username, client.Name)
authorizationCode := uuid.New().String()[:8]
if err = cache.Client.SetEx(c.Context(), cache.Prefix+"auth_code:"+authorizationCode, op.Id, 10*time.Minute); err != nil {
return resp.Resp500(c, err)
}
if uri, err = url.Parse(req.RedirectURI); err != nil {
log.Warn("[S] parse redirect uri = %s, err = %s", req.RedirectURI, err.Error())
return c.Status(http.StatusBadRequest).SendString("Bad Request: invalid redirect uri")
}
qs := uri.Query()
qs.Add("code", authorizationCode)
qs.Add("client_id", req.ClientId)
qs.Add("scope", req.Scope)
qs.Add("state", req.State)
uri.ForceQuery = true
value := uri.String() + qs.Encode()
return c.RenderHTML("approve", pageApprove, map[string]interface{}{
"redirect_uri": value,
})
}