From 75c1ae436697d49603e2ca7aed1161ed7323811f Mon Sep 17 00:00:00 2001 From: "Seele.Clover" <37256067+seeleclover@users.noreply.github.com> Date: Sun, 3 Aug 2025 00:33:52 +0800 Subject: [PATCH] feat: support nested fields for configuring user_mapping in the Custom OAuth provider (#4032) --- idp/custom.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/idp/custom.go b/idp/custom.go index b1c67b7b..7eaaf3fc 100644 --- a/idp/custom.go +++ b/idp/custom.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "net/http" + "strings" "github.com/casdoor/casdoor/util" "github.com/mitchellh/mapstructure" @@ -64,6 +65,25 @@ func (idp *CustomIdProvider) GetToken(code string) (*oauth2.Token, error) { return idp.Config.Exchange(ctx, code) } +func getNestedValue(data map[string]interface{}, path string) (interface{}, error) { + keys := strings.Split(path, ".") + var val interface{} = data + + for _, key := range keys { + m, ok := val.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("path '%s' is not valid: %s is not a map", path, key) + } + + val, ok = m[key] + if !ok { + return nil, fmt.Errorf("key '%s' not found in path '%s'", key, path) + } + } + + return val, nil +} + type CustomUserInfo struct { Id string `mapstructure:"id"` Username string `mapstructure:"username"` @@ -108,11 +128,11 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) // map user info for k, v := range idp.UserMapping { - _, ok := dataMap[v] - if !ok { - return nil, fmt.Errorf("cannot find %s in user from custom provider", v) + val, err := getNestedValue(dataMap, v) + if err != nil { + return nil, fmt.Errorf("cannot find %s in user from custom provider: %v", v, err) } - dataMap[k] = dataMap[v] + dataMap[k] = val } // try to parse id to string