feat: expand vehicle data platform capabilities

This commit is contained in:
lingniu
2026-07-27 16:46:15 +08:00
parent e3a1f80f86
commit 3c4bece72c
650 changed files with 62155 additions and 2552 deletions

View File

@@ -30,6 +30,8 @@ type apiAuthenticator struct {
mode string
tokens []tokenPrincipal
local *authStore
oneOS *oneOSIdentityAdapter
demo *demoAuthDirectory
adapters []IdentityAdapter
}
@@ -60,7 +62,17 @@ func newAPIAuthenticator(cfg config.Config, db *sql.DB) (*apiAuthenticator, erro
if err != nil {
return nil, err
}
authenticator := &apiAuthenticator{mode: mode, local: local}
oneOS, err := newOneOSIdentityAdapter(cfg)
if err != nil {
return nil, err
}
if oneOS != nil && local == nil {
return nil, fmt.Errorf("ONEOS_SSO_ENABLED requires MYSQL_DSN and the platform identity schema")
}
authenticator := &apiAuthenticator{mode: mode, local: local, oneOS: oneOS}
if mode == "disabled" && local == nil && strings.EqualFold(strings.TrimSpace(cfg.DataMode), "mock") {
authenticator.demo = newDemoAuthDirectory()
}
configured := []configuredPrincipal{}
if strings.TrimSpace(cfg.AuthTokensJSON) != "" {
if err := json.Unmarshal([]byte(cfg.AuthTokensJSON), &configured); err != nil {
@@ -97,6 +109,18 @@ func newAPIAuthenticator(cfg config.Config, db *sql.DB) (*apiAuthenticator, erro
func (a *apiAuthenticator) middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/v2/auth/oneos/exchange" {
if r.Method != http.MethodPost {
httpx.WriteError(w, http.StatusMethodNotAllowed, "METHOD_NOT_ALLOWED", "OneOS 登录兑换接口仅支持 POST", "", requestTraceID(r))
return
}
if a.oneOS == nil || a.local == nil {
httpx.WriteError(w, http.StatusServiceUnavailable, "ONEOS_SSO_UNAVAILABLE", "OneOS 单点登录尚未启用", "", requestTraceID(r))
return
}
a.local.exchangeOneOSTicket(w, r, a.oneOS)
return
}
if r.URL.Path == "/api/v2/auth/login" {
if a.local == nil {
httpx.WriteError(w, http.StatusServiceUnavailable, "LOCAL_AUTH_UNAVAILABLE", "账号登录尚未启用", "", requestTraceID(r))
@@ -146,7 +170,7 @@ func (a *apiAuthenticator) middleware(next http.Handler) http.Handler {
httpx.WriteError(w, http.StatusMethodNotAllowed, "METHOD_NOT_ALLOWED", "退出接口仅支持 POST", "", requestTraceID(r))
return
}
if a.local != nil && principal.AuthProvider == "local" {
if a.local != nil && (principal.AuthProvider == "local" || principal.AuthProvider == "oneos") {
a.local.logout(r.Context(), bearerToken(r))
}
httpx.WriteOK(w, requestTraceID(r), map[string]bool{"loggedOut": true})
@@ -163,6 +187,9 @@ func (a *apiAuthenticator) middleware(next http.Handler) http.Handler {
if a.local != nil && a.local.handleAdmin(w, r, principal) {
return
}
if a.demo != nil && a.demo.handleAdmin(w, r, principal) {
return
}
next.ServeHTTP(w, r)
})
}
@@ -220,9 +247,9 @@ func requiredMenu(r *http.Request) string {
return "shared"
case path == "/api/v2/tracks":
return "tracks"
case path == "/api/mileage/daily", path == "/api/mileage/summary", path == "/api/v2/statistics/mileage", path == "/api/vehicles/coverage", path == "/api/vehicles/coverage/summary":
case path == "/api/mileage/daily", path == "/api/mileage/summary", path == "/api/v2/statistics/mileage":
return "statistics"
case path == "/api/vehicles", path == "/api/vehicles/resolve":
case path == "/api/vehicles", path == "/api/vehicles/resolve", path == "/api/vehicles/coverage", path == "/api/vehicles/coverage/summary", path == "/api/vehicles/business-filters":
return "shared"
case strings.HasPrefix(path, "/api/v2/vehicles/"):
return "vehicles"
@@ -232,7 +259,14 @@ func requiredMenu(r *http.Request) string {
}
func requiredRole(r *http.Request) string {
if strings.HasPrefix(r.URL.Path, "/api/v2/open-platform/") {
return "admin"
}
if strings.HasPrefix(r.URL.Path, "/api/v2/reconciliation/") {
if r.Method == http.MethodPost && (strings.HasSuffix(r.URL.Path, "/archive") || strings.HasSuffix(r.URL.Path, "/restore") ||
strings.HasSuffix(r.URL.Path, "/batch-archive") || strings.HasSuffix(r.URL.Path, "/batch-restore")) {
return "admin"
}
if r.Method == http.MethodGet || r.Method == http.MethodHead || r.Method == http.MethodPost {
return "operator"
}
@@ -255,7 +289,7 @@ func requiredRole(r *http.Request) string {
switch path {
case "/api/v2/auth/logout":
return "viewer"
case "/api/vehicle-service/overviews", "/api/history/raw-frames/query", "/api/v2/access/summary", "/api/v2/access/vehicles", "/api/v2/alerts/summary", "/api/v2/alerts/events", "/api/v2/exports":
case "/api/vehicle-service/overviews", "/api/history/raw-frames/query", "/api/mileage/daily", "/api/v2/statistics/mileage", "/api/v2/access/summary", "/api/v2/access/vehicles", "/api/v2/alerts/summary", "/api/v2/alerts/events", "/api/v2/exports":
return "viewer"
case "/api/v2/alerts/notifications/read":
return "operator"
@@ -266,6 +300,9 @@ func requiredRole(r *http.Request) string {
if path == "/api/v2/alerts/rules" {
return "admin"
}
if strings.HasPrefix(path, "/api/v2/alerts/rules/") && strings.HasSuffix(path, "/rollback") {
return "admin"
}
}
if r.Method == http.MethodPut && (path == "/api/v2/access/thresholds" || strings.HasPrefix(path, "/api/v2/alerts/rules/")) {
return "admin"