feat: demo mode (#616)
This commit is contained in:
parent
d940bab0f5
commit
43000075c0
|
@ -7,6 +7,7 @@ driverName = mysql
|
|||
dataSourceName = root:123@tcp(localhost:3306)/
|
||||
dbName = casibase
|
||||
redisEndpoint =
|
||||
isDemoMode = false
|
||||
landingFolder = casibase-landing
|
||||
casdoorEndpoint = http://localhost:8000
|
||||
clientId = af6b5aa958822fb9dc33
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
package controllers
|
||||
|
||||
import "github.com/astaxie/beego/context"
|
||||
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
Msg string `json:"msg"`
|
||||
|
@ -65,3 +67,23 @@ func (c *ApiController) RequireAdmin() bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
func DenyRequest(ctx *context.Context) {
|
||||
responseError(ctx, "Unauthorized operation")
|
||||
}
|
||||
|
||||
func responseError(ctx *context.Context, error string, data ...interface{}) {
|
||||
resp := Response{Status: "error", Msg: error}
|
||||
switch len(data) {
|
||||
case 2:
|
||||
resp.Data2 = data[1]
|
||||
fallthrough
|
||||
case 1:
|
||||
resp.Data = data[0]
|
||||
}
|
||||
|
||||
err := ctx.Output.JSON(resp, true, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
1
main.go
1
main.go
|
@ -40,6 +40,7 @@ func main() {
|
|||
// https://studygolang.com/articles/2303
|
||||
beego.InsertFilter("/", beego.BeforeRouter, routers.TransparentStatic) // must has this for default page
|
||||
beego.InsertFilter("/*", beego.BeforeRouter, routers.TransparentStatic)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
|
||||
|
||||
if beego.AppConfig.String("redisEndpoint") == "" {
|
||||
beego.BConfig.WebConfig.Session.SessionProvider = "file"
|
||||
|
|
|
@ -19,6 +19,9 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casibase/conf"
|
||||
"github.com/casbin/casibase/controllers"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/casbin/casibase/util"
|
||||
|
@ -57,3 +60,38 @@ func TransparentStatic(ctx *context.Context) {
|
|||
http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html")
|
||||
}
|
||||
}
|
||||
|
||||
func ApiFilter(ctx *context.Context) {
|
||||
method := ctx.Request.Method
|
||||
urlPath := getUrlPath(ctx.Request.URL.Path)
|
||||
|
||||
if conf.IsDemoMode() {
|
||||
if !isAllowedInDemoMode(method, urlPath) {
|
||||
controllers.DenyRequest(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getUrlPath(urlPath string) string {
|
||||
if strings.HasPrefix(urlPath, "/cas") && (strings.HasSuffix(urlPath, "/serviceValidate") || strings.HasSuffix(urlPath, "/proxy") || strings.HasSuffix(urlPath, "/proxyValidate") || strings.HasSuffix(urlPath, "/validate") || strings.HasSuffix(urlPath, "/p3/serviceValidate") || strings.HasSuffix(urlPath, "/p3/proxyValidate") || strings.HasSuffix(urlPath, "/samlValidate")) {
|
||||
return "/cas"
|
||||
}
|
||||
|
||||
if strings.HasPrefix(urlPath, "/api/login/oauth") {
|
||||
return "/api/login/oauth"
|
||||
}
|
||||
|
||||
if strings.HasPrefix(urlPath, "/api/webauthn") {
|
||||
return "/api/webauthn"
|
||||
}
|
||||
|
||||
return urlPath
|
||||
}
|
||||
|
||||
func isAllowedInDemoMode(method string, urlPath string) bool {
|
||||
if method == "POST" && !(strings.HasPrefix(urlPath, "/api/signin") || urlPath == "/api/signout") {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ export const ForceLanguage = "";
|
|||
export const DefaultLanguage = "en";
|
||||
|
||||
export const AppUrl = "";
|
||||
export const IsDemoMode = false;
|
||||
|
||||
export const ThemeDefault = {
|
||||
themeType: "default",
|
||||
|
|
|
@ -648,3 +648,7 @@ export function renderExternalLink() {
|
|||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function isResponseDenied(data) {
|
||||
return data.msg === "Unauthorized operation";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2023 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Modal} from "antd";
|
||||
import {ExclamationCircleFilled} from "@ant-design/icons";
|
||||
import i18next from "i18next";
|
||||
import * as Conf from "../Conf";
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
const {confirm} = Modal;
|
||||
const {fetch: originalFetch} = window;
|
||||
|
||||
const demoModeCallback = (res) => {
|
||||
res.json().then(data => {
|
||||
if (Setting.isResponseDenied(data)) {
|
||||
confirm({
|
||||
title: i18next.t("general:This is a read-only demo site!"),
|
||||
icon: <ExclamationCircleFilled />,
|
||||
content: i18next.t("general:Go to writable demo site?"),
|
||||
okText: i18next.t("general:OK"),
|
||||
cancelText: i18next.t("general:Cancel"),
|
||||
onOk() {
|
||||
Setting.openLink(`https://demo.ai.casbin.com/${location.pathname}${location.search}?username=built-in/admin&password=123`);
|
||||
},
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const requestFilters = [];
|
||||
const responseFilters = [];
|
||||
|
||||
if (Conf.IsDemoMode) {
|
||||
responseFilters.push(demoModeCallback);
|
||||
}
|
||||
|
||||
window.fetch = async(url, option = {}) => {
|
||||
requestFilters.forEach(filter => filter(url, option));
|
||||
return new Promise((resolve, reject) => {
|
||||
originalFetch(url, option).then(res => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(res.clone());
|
||||
responseFilters.forEach(filter => filter(res.clone()));
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -28,6 +28,7 @@ import * as serviceWorker from "./serviceWorker";
|
|||
// import 'antd/dist/antd.min.css';
|
||||
import {BrowserRouter} from "react-router-dom";
|
||||
import "./i18n";
|
||||
import "./backend/FetchFilter";
|
||||
|
||||
const container = document.getElementById("root");
|
||||
|
||||
|
|
Loading…
Reference in New Issue