From 64aa9836f9ee3954aa3eb5a7c47489aeed267907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E5=85=8B=E7=8B=AE?= <42016325+A1KESH1@users.noreply.github.com> Date: Tue, 21 Nov 2023 00:02:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=EF=BC=9A=E9=A3=9E=E4=B9=A6SSO=20(#33)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new login provider "feishu_sso" * Add FeishuSSO plugin * 添加新登录插件:飞书SSO * 添加新登录插件:飞书SSO(增加通过args读取ssoid) * 添加注释:FeishuSSO Plugin * 添加注释:FeishuSSO Plugin --- .../example_feishuSSO/example_feishuSSO.go | 106 ++++++++++++++++++ .../{ => example_gitee}/example_gitee.go | 0 2 files changed, 106 insertions(+) create mode 100644 internal/provider/plugins/example/example_feishuSSO/example_feishuSSO.go rename internal/provider/plugins/example/{ => example_gitee}/example_gitee.go (100%) diff --git a/internal/provider/plugins/example/example_feishuSSO/example_feishuSSO.go b/internal/provider/plugins/example/example_feishuSSO/example_feishuSSO.go new file mode 100644 index 0000000..265b66d --- /dev/null +++ b/internal/provider/plugins/example/example_feishuSSO/example_feishuSSO.go @@ -0,0 +1,106 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + plugin "github.com/hashicorp/go-plugin" + "github.com/synctv-org/synctv/internal/provider" + "github.com/synctv-org/synctv/internal/provider/plugins" + "golang.org/x/oauth2" + "net/http" + "os" +) + +// Mac/Linux: +// go build -o feishuSSO ./internal/provider/plugins/example/example_feishuSSO/example_feishuSSO.go +// +// Windows: +// go build -o feishuSSO.exe ./internal/provider/plugins/example/example_feishuSSO/example_feishuSSO.go +// +// mv gitee {data-dir}/plugins/oauth2/feishuSSO +// +// 飞书SSO登录插件设置信息:飞书集成平台-身份集成-应用单点登录-你创建的SSO服务 +// +// config.yaml: +// +// oauth2: +// providers: +// feishuSSO: +// client_id: "App ID" +// client_secret: "App Secret" +// redirect_url: "登录回调地址" +// plugins: +// - plugin_file: plugins/oauth2/feishuSSO +// arges: +// - "OAuth2.0协议端点中的一串数字" +type FeishuProvider struct { + config oauth2.Config + ssoid string // Your SSO Application ID in Feishu Anycross +} + +func (p *FeishuProvider) Init(c provider.Oauth2Option) { + p.config.Scopes = []string{"profile"} + p.config.Endpoint = oauth2.Endpoint{ + AuthURL: fmt.Sprintf("https://anycross.feishu.cn/sso/%s/oauth2/auth", p.ssoid), // 认证端点 + TokenURL: fmt.Sprintf("https://anycross.feishu.cn/sso/%s/oauth2/token", p.ssoid), //Token 端点 + } + p.config.ClientID = c.ClientID + p.config.ClientSecret = c.ClientSecret + p.config.RedirectURL = c.RedirectURL +} + +func (p *FeishuProvider) Provider() provider.OAuth2Provider { + return "feishuSSO" //插件名 +} + +func (p *FeishuProvider) NewAuthURL(state string) string { + return p.config.AuthCodeURL(state, oauth2.AccessTypeOnline) +} + +func (p *FeishuProvider) GetToken(ctx context.Context, code string) (*oauth2.Token, error) { + return p.config.Exchange(ctx, code) +} + +func (p *FeishuProvider) RefreshToken(ctx context.Context, tk string) (*oauth2.Token, error) { + return p.config.TokenSource(ctx, &oauth2.Token{RefreshToken: tk}).Token() +} + +func (p *FeishuProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*provider.UserInfo, error) { + client := p.config.Client(ctx, tk) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://anycross.feishu.cn/sso/%s/oauth2/userinfo", p.ssoid), nil) // 身份端点 + if err != nil { + return nil, err + } + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + ui := feishuUserInfo{} + err = json.NewDecoder(resp.Body).Decode(&ui) + if err != nil { + return nil, err + } + return &provider.UserInfo{ + Username: ui.Name, + ProviderUserID: ui.UserID, + }, nil +} + +type feishuUserInfo struct { + UserID string `json:"user_id"` // 飞书UserID (企业内唯一ID) + Name string `json:"name"` // 飞书姓名(会作为SyncTV登录用户名) +} + +func main() { + args := os.Args + var pluginMap = map[string]plugin.Plugin{ + "Provider": &plugins.ProviderPlugin{Impl: &FeishuProvider{ssoid: args[1]}}, + } + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: plugins.HandshakeConfig, + Plugins: pluginMap, + GRPCServer: plugin.DefaultGRPCServer, + }) +} diff --git a/internal/provider/plugins/example/example_gitee.go b/internal/provider/plugins/example/example_gitee/example_gitee.go similarity index 100% rename from internal/provider/plugins/example/example_gitee.go rename to internal/provider/plugins/example/example_gitee/example_gitee.go