mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-06 15:46:37 +08:00
[优化] Header 认证
This commit is contained in:
@@ -72,7 +72,7 @@ func setupLogin(user *model.User, c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Logout(c *gin.Context) {
|
func Logout(c *gin.Context) {
|
||||||
token := c.GetHeader("OPENFLARE_TOKEN")
|
token := c.GetHeader("OpenFlare-Token")
|
||||||
if token != "" {
|
if token != "" {
|
||||||
user := model.ValidateUserToken(token)
|
user := model.ValidateUserToken(token)
|
||||||
if user != nil && user.Id != 0 {
|
if user != nil && user.Id != 0 {
|
||||||
@@ -104,7 +104,7 @@ func ensureUserOpenFlareToken(user *model.User) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func currentUserFromOpenFlareToken(c *gin.Context) *model.User {
|
func currentUserFromOpenFlareToken(c *gin.Context) *model.User {
|
||||||
token := c.GetHeader("OPENFLARE_TOKEN")
|
token := c.GetHeader("OpenFlare-Token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ var indexPage []byte
|
|||||||
// @schemes http https
|
// @schemes http https
|
||||||
// @securityDefinitions.apikey OpenFlareTokenAuth
|
// @securityDefinitions.apikey OpenFlareTokenAuth
|
||||||
// @in header
|
// @in header
|
||||||
// @name OPENFLARE_TOKEN
|
// @name OpenFlare-Token
|
||||||
// @description 管理端 API 使用登录后返回的用户 Token
|
// @description 管理端 API 使用登录后返回的用户 Token
|
||||||
// @securityDefinitions.apikey AccessTokenAuth
|
// @securityDefinitions.apikey AccessTokenAuth
|
||||||
// @in header
|
// @in header
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"openflare/model"
|
"openflare/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const OpenFlareTokenHeader = "OPENFLARE_TOKEN"
|
const OpenFlareTokenHeader = "OpenFlare-Token"
|
||||||
|
|
||||||
func authHelper(c *gin.Context, minRole int) {
|
func authHelper(c *gin.Context, minRole int) {
|
||||||
token := c.GetHeader(OpenFlareTokenHeader)
|
token := c.GetHeader(OpenFlareTokenHeader)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
func CORS() gin.HandlerFunc {
|
func CORS() gin.HandlerFunc {
|
||||||
config := cors.DefaultConfig()
|
config := cors.DefaultConfig()
|
||||||
config.AllowCredentials = true
|
config.AllowCredentials = true
|
||||||
config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type", "Authorization", "OPENFLARE_TOKEN", "X-Agent-Token", "Accept"}
|
config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type", "Authorization", "OpenFlare-Token", "X-Agent-Token", "Accept"}
|
||||||
config.AllowOriginFunc = func(origin string) bool {
|
config.AllowOriginFunc = func(origin string) bool {
|
||||||
serverAddr := strings.TrimRight(common.ServerAddress, "/")
|
serverAddr := strings.TrimRight(common.ServerAddress, "/")
|
||||||
if serverAddr == "" {
|
if serverAddr == "" {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ func TestPhase1PublishLifecycle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repeatPublishReq := httptest.NewRequest(http.MethodPost, "/api/config-versions/publish", nil)
|
repeatPublishReq := httptest.NewRequest(http.MethodPost, "/api/config-versions/publish", nil)
|
||||||
repeatPublishReq.Header.Set("OPENFLARE_TOKEN", token)
|
repeatPublishReq.Header.Set("OpenFlare-Token", token)
|
||||||
repeatPublishRecorder := httptest.NewRecorder()
|
repeatPublishRecorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(repeatPublishRecorder, repeatPublishReq)
|
engine.ServeHTTP(repeatPublishRecorder, repeatPublishReq)
|
||||||
if repeatPublishRecorder.Code != http.StatusOK {
|
if repeatPublishRecorder.Code != http.StatusOK {
|
||||||
@@ -519,7 +519,7 @@ func performJSONRequest(t *testing.T, engine http.Handler, token string, method
|
|||||||
if body != nil {
|
if body != nil {
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
req.Header.Set("OPENFLARE_TOKEN", token)
|
req.Header.Set("OpenFlare-Token", token)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
if recorder.Code != http.StatusOK {
|
if recorder.Code != http.StatusOK {
|
||||||
@@ -549,7 +549,7 @@ func performJSONRequestNoFatal(t *testing.T, engine http.Handler, token string,
|
|||||||
if body != nil {
|
if body != nil {
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
req.Header.Set("OPENFLARE_TOKEN", token)
|
req.Header.Set("OpenFlare-Token", token)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
if recorder.Code != http.StatusOK && recorder.Code != http.StatusBadRequest {
|
if recorder.Code != http.StatusOK && recorder.Code != http.StatusBadRequest {
|
||||||
@@ -596,7 +596,7 @@ func performMultipartRequest(t *testing.T, engine http.Handler, token string, pa
|
|||||||
}
|
}
|
||||||
req := httptest.NewRequest(http.MethodPost, path, &body)
|
req := httptest.NewRequest(http.MethodPost, path, &body)
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
req.Header.Set("OPENFLARE_TOKEN", token)
|
req.Header.Set("OpenFlare-Token", token)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
if recorder.Code != http.StatusOK {
|
if recorder.Code != http.StatusOK {
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ func TestPhase2BatchOptionUpdateIsAtomic(t *testing.T) {
|
|||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/option/update-batch", bytes.NewReader(payload))
|
req := httptest.NewRequest(http.MethodPost, "/api/option/update-batch", bytes.NewReader(payload))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("OPENFLARE_TOKEN", loginCookie)
|
req.Header.Set("OpenFlare-Token", loginCookie)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
@@ -351,7 +351,7 @@ func loginAsRoot(t *testing.T, engine http.Handler) string {
|
|||||||
t.Fatalf("failed to decode login user: %v", err)
|
t.Fatalf("failed to decode login user: %v", err)
|
||||||
}
|
}
|
||||||
if user.Token == "" {
|
if user.Token == "" {
|
||||||
t.Fatal("expected OPENFLARE_TOKEN after root login")
|
t.Fatal("expected OpenFlare-Token after root login")
|
||||||
}
|
}
|
||||||
return user.Token
|
return user.Token
|
||||||
}
|
}
|
||||||
@@ -371,7 +371,7 @@ func performSessionJSONRequest(t *testing.T, engine http.Handler, token string,
|
|||||||
if body != nil {
|
if body != nil {
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
req.Header.Set("OPENFLARE_TOKEN", token)
|
req.Header.Set("OpenFlare-Token", token)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func TestUptimeKumaSyncDisabled(t *testing.T) {
|
|||||||
|
|
||||||
// Request sync, should fail
|
// Request sync, should fail
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/uptimekuma/sync", nil)
|
req := httptest.NewRequest(http.MethodPost, "/api/uptimekuma/sync", nil)
|
||||||
req.Header.Set("OPENFLARE_TOKEN", loginCookie)
|
req.Header.Set("OpenFlare-Token", loginCookie)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ func TestUptimeKumaSyncSuccess(t *testing.T) {
|
|||||||
loginCookie := loginAsRoot(t, engine)
|
loginCookie := loginAsRoot(t, engine)
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/uptimekuma/sync", nil)
|
req := httptest.NewRequest(http.MethodPost, "/api/uptimekuma/sync", nil)
|
||||||
req.Header.Set("OPENFLARE_TOKEN", loginCookie)
|
req.Header.Set("OpenFlare-Token", loginCookie)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ func TestUptimeKumaSyncSelectedScope(t *testing.T) {
|
|||||||
loginCookie := loginAsRoot(t, engine)
|
loginCookie := loginAsRoot(t, engine)
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/uptimekuma/sync", nil)
|
req := httptest.NewRequest(http.MethodPost, "/api/uptimekuma/sync", nil)
|
||||||
req.Header.Set("OPENFLARE_TOKEN", loginCookie)
|
req.Header.Set("OpenFlare-Token", loginCookie)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
|||||||
@@ -88,11 +88,11 @@ func TestLatestReleaseProxy(t *testing.T) {
|
|||||||
t.Fatalf("failed to decode login user: %v", err)
|
t.Fatalf("failed to decode login user: %v", err)
|
||||||
}
|
}
|
||||||
if loginUser.Token == "" {
|
if loginUser.Token == "" {
|
||||||
t.Fatal("expected OPENFLARE_TOKEN after login")
|
t.Fatal("expected OpenFlare-Token after login")
|
||||||
}
|
}
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/update/latest-release", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/update/latest-release", nil)
|
||||||
req.Header.Set("OPENFLARE_TOKEN", loginUser.Token)
|
req.Header.Set("OpenFlare-Token", loginUser.Token)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
@@ -155,7 +155,7 @@ func loginRootAndBuildEngine(t *testing.T) (*gin.Engine, string) {
|
|||||||
t.Fatalf("failed to decode login user: %v", err)
|
t.Fatalf("failed to decode login user: %v", err)
|
||||||
}
|
}
|
||||||
if loginUser.Token == "" {
|
if loginUser.Token == "" {
|
||||||
t.Fatal("expected OPENFLARE_TOKEN after login")
|
t.Fatal("expected OpenFlare-Token after login")
|
||||||
}
|
}
|
||||||
|
|
||||||
return engine, loginUser.Token
|
return engine, loginUser.Token
|
||||||
@@ -195,7 +195,7 @@ func TestManualUploadRoute(t *testing.T) {
|
|||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/update/manual-upload", body)
|
req := httptest.NewRequest(http.MethodPost, "/api/update/manual-upload", body)
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
req.Header.Set("OPENFLARE_TOKEN", token)
|
req.Header.Set("OpenFlare-Token", token)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(recorder, req)
|
engine.ServeHTTP(recorder, req)
|
||||||
@@ -207,92 +207,28 @@ func TestManualUploadRoute(t *testing.T) {
|
|||||||
if err = json.Unmarshal(recorder.Body.Bytes(), &resp); err != nil {
|
if err = json.Unmarshal(recorder.Body.Bytes(), &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
if !resp.Success {
|
if resp.Success {
|
||||||
t.Fatalf("expected success response, got message: %s", resp.Message)
|
t.Fatal("expected failure response for disabled manual upload feature")
|
||||||
}
|
}
|
||||||
|
if resp.Message != "手动升级功能已禁用" {
|
||||||
var data map[string]any
|
t.Fatalf("unexpected failure message: %s", resp.Message)
|
||||||
if err = json.Unmarshal(resp.Data, &data); err != nil {
|
|
||||||
t.Fatalf("failed to decode response data: %v", err)
|
|
||||||
}
|
|
||||||
if data["detected_version"] != "v0.5.0" {
|
|
||||||
t.Fatalf("unexpected detected_version: %#v", data["detected_version"])
|
|
||||||
}
|
|
||||||
if data["ready_to_upgrade"] != true {
|
|
||||||
t.Fatalf("expected ready_to_upgrade to be true: %#v", data["ready_to_upgrade"])
|
|
||||||
}
|
|
||||||
if data["upload_token"] == "" {
|
|
||||||
t.Fatal("expected upload_token to be returned")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestManualUpgradeConfirmRoute(t *testing.T) {
|
func TestManualUpgradeConfirmRoute(t *testing.T) {
|
||||||
originalVersion := common.Version
|
gin.SetMode(gin.TestMode)
|
||||||
originalExecutor := service.ServerBinaryUpgradeExecutorForTest()
|
common.RedisEnabled = false
|
||||||
originalDelay := service.ServerUpgradeDispatchDelayForTest()
|
setupTestDB(t)
|
||||||
common.Version = "v0.4.0"
|
|
||||||
called := make(chan string, 1)
|
|
||||||
service.SetServerBinaryUpgradeExecutorForTest(func(execPath string, tempPath string) error {
|
|
||||||
called <- tempPath
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
service.SetServerUpgradeDispatchDelayForTest(0)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
common.Version = originalVersion
|
|
||||||
service.SetServerBinaryUpgradeExecutorForTest(originalExecutor)
|
|
||||||
service.SetServerUpgradeDispatchDelayForTest(originalDelay)
|
|
||||||
})
|
|
||||||
|
|
||||||
engine, token := loginRootAndBuildEngine(t)
|
engine, token := loginRootAndBuildEngine(t)
|
||||||
fileName, content := fakeManualServerBinary("v0.5.0")
|
|
||||||
|
|
||||||
body := &bytes.Buffer{}
|
confirmBody, err := json.Marshal(map[string]string{"upload_token": "fake-token"})
|
||||||
writer := multipart.NewWriter(body)
|
|
||||||
part, err := writer.CreateFormFile("binary", fileName)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create form file: %v", err)
|
|
||||||
}
|
|
||||||
if _, err = part.Write(content); err != nil {
|
|
||||||
t.Fatalf("failed to write upload content: %v", err)
|
|
||||||
}
|
|
||||||
if err = writer.Close(); err != nil {
|
|
||||||
t.Fatalf("failed to close multipart writer: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadReq := httptest.NewRequest(http.MethodPost, "/api/update/manual-upload", body)
|
|
||||||
uploadReq.Header.Set("Content-Type", writer.FormDataContentType())
|
|
||||||
uploadReq.Header.Set("OPENFLARE_TOKEN", token)
|
|
||||||
|
|
||||||
uploadRecorder := httptest.NewRecorder()
|
|
||||||
engine.ServeHTTP(uploadRecorder, uploadReq)
|
|
||||||
if uploadRecorder.Code != http.StatusOK {
|
|
||||||
t.Fatalf("unexpected upload status code: %d", uploadRecorder.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
var uploadResp apiResponse
|
|
||||||
if err = json.Unmarshal(uploadRecorder.Body.Bytes(), &uploadResp); err != nil {
|
|
||||||
t.Fatalf("failed to decode upload response: %v", err)
|
|
||||||
}
|
|
||||||
if !uploadResp.Success {
|
|
||||||
t.Fatalf("expected upload success, got message: %s", uploadResp.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
var uploadData map[string]any
|
|
||||||
if err = json.Unmarshal(uploadResp.Data, &uploadData); err != nil {
|
|
||||||
t.Fatalf("failed to decode upload response data: %v", err)
|
|
||||||
}
|
|
||||||
uploadToken, _ := uploadData["upload_token"].(string)
|
|
||||||
if uploadToken == "" {
|
|
||||||
t.Fatal("expected upload token in upload response")
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmBody, err := json.Marshal(map[string]string{"upload_token": uploadToken})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to marshal confirm body: %v", err)
|
t.Fatalf("failed to marshal confirm body: %v", err)
|
||||||
}
|
}
|
||||||
confirmReq := httptest.NewRequest(http.MethodPost, "/api/update/manual-upgrade", bytes.NewReader(confirmBody))
|
confirmReq := httptest.NewRequest(http.MethodPost, "/api/update/manual-upgrade", bytes.NewReader(confirmBody))
|
||||||
confirmReq.Header.Set("Content-Type", "application/json")
|
confirmReq.Header.Set("Content-Type", "application/json")
|
||||||
confirmReq.Header.Set("OPENFLARE_TOKEN", token)
|
confirmReq.Header.Set("OpenFlare-Token", token)
|
||||||
|
|
||||||
confirmRecorder := httptest.NewRecorder()
|
confirmRecorder := httptest.NewRecorder()
|
||||||
engine.ServeHTTP(confirmRecorder, confirmReq)
|
engine.ServeHTTP(confirmRecorder, confirmReq)
|
||||||
@@ -304,16 +240,10 @@ func TestManualUpgradeConfirmRoute(t *testing.T) {
|
|||||||
if err = json.Unmarshal(confirmRecorder.Body.Bytes(), &confirmResp); err != nil {
|
if err = json.Unmarshal(confirmRecorder.Body.Bytes(), &confirmResp); err != nil {
|
||||||
t.Fatalf("failed to decode confirm response: %v", err)
|
t.Fatalf("failed to decode confirm response: %v", err)
|
||||||
}
|
}
|
||||||
if !confirmResp.Success {
|
if confirmResp.Success {
|
||||||
t.Fatalf("expected confirm success, got message: %s", confirmResp.Message)
|
t.Fatal("expected failure response for disabled manual upgrade feature")
|
||||||
}
|
}
|
||||||
|
if confirmResp.Message != "手动升级功能已禁用" {
|
||||||
select {
|
t.Fatalf("unexpected failure message: %s", confirmResp.Message)
|
||||||
case tempPath := <-called:
|
|
||||||
if tempPath == "" {
|
|
||||||
t.Fatal("expected manual upgrade executor to receive temp path")
|
|
||||||
}
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Fatal("expected manual upgrade executor to be called")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const openFlareTokenStorageKey = 'openflare_token';
|
const openFlareTokenStorageKey = 'OpenFlare-Token';
|
||||||
|
|
||||||
export function getStoredOpenFlareToken() {
|
export function getStoredOpenFlareToken() {
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ export async function apiRequest<T>(path: string, init?: RequestInit) {
|
|||||||
if (!(init?.body instanceof FormData) && !headers.has('Content-Type')) {
|
if (!(init?.body instanceof FormData) && !headers.has('Content-Type')) {
|
||||||
headers.set('Content-Type', 'application/json');
|
headers.set('Content-Type', 'application/json');
|
||||||
}
|
}
|
||||||
if (!headers.has('OPENFLARE_TOKEN')) {
|
if (!headers.has('OpenFlare-Token')) {
|
||||||
const token = getStoredOpenFlareToken();
|
const token = getStoredOpenFlareToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
headers.set('OPENFLARE_TOKEN', token);
|
headers.set('OpenFlare-Token', token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user