Use uni-token

💄 A lot of optimization
This commit is contained in:
2024-02-21 22:58:51 +08:00
parent 4101043d65
commit 1e04f2029f
50 changed files with 319 additions and 490 deletions

View File

@ -1,35 +1,51 @@
package server
import (
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
"code.smartsheep.studio/hydrogen/interactive/pkg/security"
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/keyauth"
"strconv"
"strings"
)
var auth = keyauth.New(keyauth.Config{
KeyLookup: "header:Authorization",
AuthScheme: "Bearer",
Validator: func(c *fiber.Ctx, token string) (bool, error) {
claims, err := security.DecodeJwt(token)
if err != nil {
return false, err
func authMiddleware(c *fiber.Ctx) error {
var token string
if cookie := c.Cookies(security.CookieAccessKey); len(cookie) > 0 {
token = cookie
}
if header := c.Get(fiber.HeaderAuthorization); len(header) > 0 {
tk := strings.Replace(header, "Bearer", "", 1)
token = strings.TrimSpace(tk)
}
c.Locals("token", token)
if err := authFunc(c); err != nil {
return err
}
return c.Next()
}
func authFunc(c *fiber.Ctx, overrides ...string) error {
var token string
if len(overrides) > 0 {
token = overrides[0]
} else {
if tk, ok := c.Locals("token").(string); !ok {
return fiber.NewError(fiber.StatusUnauthorized)
} else {
token = tk
}
}
id, _ := strconv.Atoi(claims.Subject)
var user models.Account
if err := database.C.Where(&models.Account{
BaseModel: models.BaseModel{ID: uint(id)},
}).First(&user).Error; err != nil {
return false, err
rtk := c.Cookies(security.CookieRefreshKey)
if user, atk, rtk, err := services.Authenticate(token, rtk); err == nil {
if atk != token {
security.SetJwtCookieSet(c, atk, rtk)
}
c.Locals("principal", user)
return true, nil
},
ContextKey: "token",
})
return nil
} else {
return err
}
}

View File

@ -1,93 +0,0 @@
package server
import (
"code.smartsheep.studio/hydrogen/interactive/pkg/services"
"context"
"encoding/json"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/spf13/viper"
"golang.org/x/oauth2"
)
var cfg oauth2.Config
func buildOauth2Config() {
cfg = oauth2.Config{
RedirectURL: fmt.Sprintf("https://%s/auth/callback", viper.GetString("domain")),
ClientID: viper.GetString("identity.client_id"),
ClientSecret: viper.GetString("identity.client_secret"),
Scopes: []string{"openid"},
Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("%s/auth/o/connect", viper.GetString("identity.endpoint")),
TokenURL: fmt.Sprintf("%s/api/auth/token", viper.GetString("identity.endpoint")),
AuthStyle: oauth2.AuthStyleInParams,
},
}
}
func doLogin(c *fiber.Ctx) error {
buildOauth2Config()
url := cfg.AuthCodeURL(uuid.NewString())
return c.JSON(fiber.Map{
"target": url,
})
}
func postLogin(c *fiber.Ctx) error {
buildOauth2Config()
code := c.Query("code")
token, err := cfg.Exchange(context.Background(), code)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to exchange token: %q", err))
}
agent := fiber.
Get(fmt.Sprintf("%s/api/users/me", viper.GetString("identity.endpoint"))).
Set(fiber.HeaderAuthorization, fmt.Sprintf("Bearer %s", token.AccessToken))
_, body, errs := agent.Bytes()
if len(errs) > 0 {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to get userinfo: %q", errs))
}
var userinfo services.IdentityUserinfo
err = json.Unmarshal(body, &userinfo)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to parse userinfo: %q", err))
}
account, err := services.LinkAccount(userinfo)
access, refresh, err := services.GetToken(account)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to get token: %q", err))
}
return c.JSON(fiber.Map{
"access_token": access,
"refresh_token": refresh,
})
}
func doRefreshToken(c *fiber.Ctx) error {
var data struct {
RefreshToken string `json:"refresh_token" validate:"required"`
}
if err := BindAndValidate(c, &data); err != nil {
return err
}
access, refresh, err := services.RefreshToken(data.RefreshToken)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to get token: %q", err))
}
return c.JSON(fiber.Map{
"access_token": access,
"refresh_token": refresh,
})
}

View File

@ -58,45 +58,41 @@ func NewServer() {
api := A.Group("/api").Name("API")
{
api.Get("/auth", doLogin)
api.Get("/auth/callback", postLogin)
api.Post("/auth/refresh", doRefreshToken)
api.Get("/users/me", auth, getUserinfo)
api.Get("/users/me", authMiddleware, getUserinfo)
api.Get("/users/:accountId", getOthersInfo)
api.Get("/users/:accountId/follow", auth, getAccountFollowed)
api.Post("/users/:accountId/follow", auth, doFollowAccount)
api.Get("/users/:accountId/follow", authMiddleware, getAccountFollowed)
api.Post("/users/:accountId/follow", authMiddleware, doFollowAccount)
api.Get("/attachments/o/:fileId", cache.New(cache.Config{
Expiration: 365 * 24 * time.Hour,
CacheControl: true,
}), openAttachment)
api.Post("/attachments", auth, uploadAttachment)
api.Post("/attachments", authMiddleware, uploadAttachment)
api.Get("/posts", listPost)
api.Get("/posts/:postId", getPost)
api.Post("/posts", auth, createPost)
api.Post("/posts/:postId/react/:reactType", auth, reactPost)
api.Put("/posts/:postId", auth, editPost)
api.Delete("/posts/:postId", auth, deletePost)
api.Post("/posts", authMiddleware, createPost)
api.Post("/posts/:postId/react/:reactType", authMiddleware, reactPost)
api.Put("/posts/:postId", authMiddleware, editPost)
api.Delete("/posts/:postId", authMiddleware, deletePost)
api.Get("/categories", listCategroies)
api.Post("/categories", auth, newCategory)
api.Put("/categories/:categoryId", auth, editCategory)
api.Delete("/categories/:categoryId", auth, deleteCategory)
api.Post("/categories", authMiddleware, newCategory)
api.Put("/categories/:categoryId", authMiddleware, editCategory)
api.Delete("/categories/:categoryId", authMiddleware, deleteCategory)
api.Get("/creators/posts", auth, listOwnPost)
api.Get("/creators/posts/:postId", auth, getOwnPost)
api.Get("/creators/posts", authMiddleware, listOwnPost)
api.Get("/creators/posts/:postId", authMiddleware, getOwnPost)
api.Get("/realms", listRealm)
api.Get("/realms/me", auth, listOwnedRealm)
api.Get("/realms/me/available", auth, listAvailableRealm)
api.Get("/realms/me", authMiddleware, listOwnedRealm)
api.Get("/realms/me/available", authMiddleware, listAvailableRealm)
api.Get("/realms/:realmId", getRealm)
api.Post("/realms", auth, createRealm)
api.Post("/realms/:realmId/invite", auth, inviteRealm)
api.Post("/realms/:realmId/kick", auth, kickRealm)
api.Put("/realms/:realmId", auth, editRealm)
api.Delete("/realms/:realmId", auth, deleteRealm)
api.Post("/realms", authMiddleware, createRealm)
api.Post("/realms/:realmId/invite", authMiddleware, inviteRealm)
api.Post("/realms/:realmId/kick", authMiddleware, kickRealm)
api.Put("/realms/:realmId", authMiddleware, editRealm)
api.Delete("/realms/:realmId", authMiddleware, deleteRealm)
}
A.Use("/", cache.New(cache.Config{

View File

@ -9,5 +9,8 @@ func getMetadata(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"name": viper.GetString("name"),
"domain": viper.GetString("domain"),
"components": fiber.Map{
"identity": viper.GetString("identity.endpoint"),
},
})
}