feat(auth): allow JWT IP changes by configuration (#1236)

* feat(auth): allow JWT IP changes by configuration

* fix(auth): make JWT IP change setting concurrency-safe

* test(auth): move JWT IP change setting tests out of MCP test file
This commit is contained in:
NikoCat233 authored and GitHub committed 2026-09-12 22:59:17 +08:00
1 parent 8cb86e3853
commit d19952a834
8 files changed
+172 -2

No files matched your search

+21
View File
@@ -61,6 +61,9 @@ type ConfigDashboard struct {
AdminTemplate string `koanf:"admin_template" json:"admin_template,omitempty"`
EnablePlainIPInNotification bool `koanf:"enable_plain_ip_in_notification" json:"enable_plain_ip_in_notification,omitempty"` // 通知信息IP不打码
// AllowJWTIPChange disables the IP binding check for browser login sessions.
// Keep this disabled by default so a stolen JWT remains bound to its issuing IP.
AllowJWTIPChange bool `koanf:"allow_jwt_ip_change" json:"allow_jwt_ip_change,omitempty"`
EnableMCP bool `koanf:"enable_mcp" json:"enable_mcp,omitempty"` // 是否启用 MCP 入口(默认关闭;启用前请审视 PAT scope/whitelist)
@@ -103,6 +106,10 @@ type Config struct {
// SettingResponse 按值拷贝 ConfigDashboard 触发 copylocks。
mcpEnabled atomic.Bool `koanf:"-" json:"-" yaml:"-"`
// jwtIPChangeAllowed mirrors AllowJWTIPChange for concurrent authentication
// and setting updates. Keep atomic fields outside ConfigDashboard.
jwtIPChangeAllowed atomic.Bool `koanf:"-" json:"-" yaml:"-"`
// oauth2 配置
Oauth2 map[string]*Oauth2Config `koanf:"oauth2" json:"oauth2,omitempty"`
@@ -225,6 +232,8 @@ func (c *Config) Read(path string, frontendTemplates []FrontendTemplate) error {
c.JWTTimeout = 1
}
c.jwtIPChangeAllowed.Store(c.AllowJWTIPChange)
if c.AgentSecretKey == "" {
c.AgentSecretKey, err = utils.GenerateRandomString(32)
if err != nil {
@@ -252,6 +261,17 @@ func (c *Config) SetMCPEnabled(v bool) {
c.mcpEnabled.Store(v)
}
// JWTIPChangeAllowed reports whether JWT sessions may change IP concurrently.
func (c *Config) JWTIPChangeAllowed() bool {
return c.jwtIPChangeAllowed.Load()
}
// SetJWTIPChangeAllowed updates only the atomic mirror. save() synchronizes
// the public field for persistence; authentication must use the accessor.
func (c *Config) SetJWTIPChangeAllowed(v bool) {
c.jwtIPChangeAllowed.Store(v)
}
// Save 保存配置文件
func (c *Config) Save() error {
return c.save()
@@ -320,6 +340,7 @@ func (c *Config) patchYAMLField(key string, value any) error {
func (c *Config) save() error {
c.EnableMCP = c.mcpEnabled.Load()
c.AllowJWTIPChange = c.jwtIPChangeAllowed.Load()
data, err := yaml.Marshal(c)
if err != nil {
return err