diff --git a/service/middleware.go b/service/middleware.go
index 77b7d9d8..977122db 100644
--- a/service/middleware.go
+++ b/service/middleware.go
@@ -1,6 +1,7 @@
package service
import (
+ "fmt"
"path/filepath"
"strings"
@@ -81,6 +82,13 @@ func withStaticFileServer(c *gin.Context) {
html, code, err := r.Render()
if err != nil {
+ if code == 301 || code == 302 {
+ fmt.Println(err.Error())
+ c.Redirect(code, err.Error())
+ c.Done()
+ return
+ }
+
log.Error("Sui Render Error: %s", err.Error())
c.AbortWithError(code, err)
return
diff --git a/sui/api/guards.go b/sui/api/guards.go
new file mode 100644
index 00000000..8dbe93fe
--- /dev/null
+++ b/sui/api/guards.go
@@ -0,0 +1,141 @@
+package api
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/yaoapp/gou/process"
+ "github.com/yaoapp/yao/helper"
+)
+
+// Guards middlewares
+var Guards = map[string]func(c *gin.Context) error{
+ "bearer-jwt": guardBearerJWT, // Bearer JWT
+ "query-jwt": guardQueryJWT, // Get JWT Token from query string "__tk"
+ "cookie-jwt": guardCookieJWT, // Get JWT Token from cookie "__tk"
+
+}
+
+// JWT Bearer JWT
+func guardBearerJWT(c *gin.Context) error {
+
+ tokenString := c.Request.Header.Get("Authorization")
+ tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
+ if tokenString == "" {
+ c.JSON(403, gin.H{"code": 403, "message": "No permission"})
+ c.Abort()
+ return fmt.Errorf("No permission")
+ }
+
+ claims := helper.JwtValidate(tokenString)
+ c.Set("__sid", claims.SID)
+ return nil
+}
+
+// JWT Bearer JWT
+func guardCookieJWT(c *gin.Context) error {
+ tokenString, err := c.Cookie("__tk")
+ if err != nil {
+ c.JSON(403, gin.H{"code": 403, "message": "No permission"})
+ c.Abort()
+ return fmt.Errorf("No permission")
+ }
+
+ if tokenString == "" {
+ c.JSON(403, gin.H{"code": 403, "message": "No permission"})
+ c.Abort()
+ return fmt.Errorf("No permission")
+ }
+
+ claims := helper.JwtValidate(tokenString)
+ c.Set("__sid", claims.SID)
+ return nil
+}
+
+// JWT Bearer JWT
+func guardQueryJWT(c *gin.Context) error {
+ tokenString := c.Query("__tk")
+ if tokenString == "" {
+ c.JSON(403, gin.H{"code": 403, "message": "No permission"})
+ c.Abort()
+ return fmt.Errorf("No permission")
+ }
+
+ claims := helper.JwtValidate(tokenString)
+ c.Set("__sid", claims.SID)
+ return nil
+}
+
+// ProcessGuard guard process
+func (r *Request) processGuard(name string) error {
+ var body interface{}
+ c := r.context
+
+ if c.Request.Body != nil {
+
+ bodyBytes, err := io.ReadAll(c.Request.Body)
+ if err == nil {
+ if strings.HasPrefix(strings.ToLower(c.Request.Header.Get("Content-Type")), "application/json") {
+ jsoniter.Unmarshal(bodyBytes, &body)
+ } else {
+ body = string(bodyBytes)
+ }
+ }
+
+ // Reset body
+ c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
+ }
+
+ params := map[string]string{}
+ for _, param := range c.Params {
+ params[param.Key] = param.Value
+ }
+
+ args := []interface{}{
+ r.URL, // page url
+ r.Params, // page params
+ r.Query, // query string
+ r.Payload, // payload
+ r.Headers, // Request headers
+ }
+
+ process, err := process.Of(name, args...)
+ if err != nil {
+ c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())})
+ c.Abort()
+ return err
+ }
+
+ if sid, has := c.Get("__sid"); has { // 设定会话ID
+ if sid, ok := sid.(string); ok {
+ process.WithSID(sid)
+ }
+ }
+
+ if global, has := c.Get("__global"); has { // 设定全局变量
+ if global, ok := global.(map[string]interface{}); ok {
+ process.WithGlobal(global)
+ }
+ }
+
+ v, err := process.Exec()
+ if err != nil {
+ return err
+ }
+
+ if data, ok := v.(map[string]interface{}); ok {
+ if sid, ok := data["__sid"].(string); ok {
+ c.Set("__sid", sid)
+ }
+
+ if global, ok := data["__global"].(map[string]interface{}); ok {
+ c.Set("__global", global)
+ }
+ }
+
+ return nil
+}
diff --git a/sui/api/request.go b/sui/api/request.go
index 5e6fdf5b..316eaf10 100644
--- a/sui/api/request.go
+++ b/sui/api/request.go
@@ -8,7 +8,9 @@ import (
"strings"
"github.com/gin-gonic/gin"
+ jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/application"
+ "github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/sui/core"
)
@@ -17,6 +19,7 @@ import (
type Request struct {
File string
*core.Request
+ context *gin.Context
}
// NewRequestContext is the constructor for Request.
@@ -45,7 +48,8 @@ func NewRequestContext(c *gin.Context) (*Request, int, error) {
path := strings.TrimSuffix(c.Request.URL.Path, ".sui")
return &Request{
- File: file,
+ File: file,
+ context: c,
Request: &core.Request{
Method: c.Request.Method,
Query: c.Request.URL.Query(),
@@ -82,6 +86,21 @@ func (r *Request) Render() (string, int, error) {
return "", 500, err
}
+ guard := ""
+ configText := ""
+ configSel := doc.Find("script[name=config]")
+ if configSel != nil && configSel.Length() > 0 {
+ configText = configSel.Text()
+ configSel.Remove()
+
+ var conf core.PageConfig
+ err := jsoniter.UnmarshalFromString(configText, &conf)
+ if err != nil {
+ return "", 500, fmt.Errorf("config error, please re-complie the page %s", err.Error())
+ }
+ guard = conf.Guard
+ }
+
dataText := ""
dataSel := doc.Find("script[name=data]")
if dataSel != nil && dataSel.Length() > 0 {
@@ -107,10 +126,31 @@ func (r *Request) Render() (string, int, error) {
Data: dataText,
Global: globalDataText,
HTML: html,
+ Guard: guard,
+ Config: configText,
}
log.Trace("The page %s is cached", r.File)
}
+ // Guard the page
+ if c.Guard != "" && r.context != nil {
+
+ if guard, has := Guards[c.Guard]; has {
+ err := guard(r.context)
+ if err != nil {
+ ex := exception.Err(err, 403)
+ return "", ex.Code, fmt.Errorf("%s", ex.Message)
+ }
+ } else {
+ // Process the guard
+ err := r.processGuard(c.Guard)
+ if err != nil {
+ ex := exception.Err(err, 403)
+ return "", ex.Code, fmt.Errorf("%s", ex.Message)
+ }
+ }
+ }
+
var err error
data := core.Data{}
if c.Data != "" {
@@ -128,6 +168,12 @@ func (r *Request) Render() (string, int, error) {
data["$global"] = global
}
+ // Set the page request data
+ data["$payload"] = r.Request.Payload
+ data["$query"] = r.Request.Query
+ data["$param"] = r.Request.Params
+ data["$url"] = r.Request.URL
+
printData := false
if r.Query != nil && r.Query.Has("__sui_print_data") {
printData = true
diff --git a/sui/core/compile.go b/sui/core/compile.go
index 0c2cc37f..35da3ad3 100644
--- a/sui/core/compile.go
+++ b/sui/core/compile.go
@@ -29,6 +29,17 @@ func (page *Page) Compile(option *BuildOption) (string, error) {
}
}
+ // Page Config
+ page.Config = page.GetConfig()
+
+ // Config Data
+ if page.Config != nil {
+ doc.Find("body").AppendHtml("\n\n" + `\n\n",
+ )
+ }
+
// Page Data
if page.Codes.DATA.Code != "" {
doc.Find("body").AppendHtml("\n\n" + `