;开发人员;构建插件;为数据源插件添加身份验证

为数据源插件添加身份验证

本页面解释了如何配置数据源插件以根据第三方API进行身份验证。

有两种方法可以从插件执行身份验证请求—使用数据源代理,或通过建立一个后端插件.你的选择取决于你的插件如何根据第三方API进行身份验证。

  • 如果需要使用基本身份验证或API密钥进行身份验证,请使用数据源代理
  • 如果API使用客户端凭证支持OAuth 2.0,则使用数据源代理
  • 如果API使用数据源代理不支持的自定义身份验证方法,或者API通过不同于HTTP的协议进行通信,请使用后端插件

无论使用哪种方法,首先都需要加密插件需要存储的敏感信息。

加密数据源配置

数据源插件有两种存储自定义配置的方式:jsonData而且secureJsonData

拥有查看器的内容可以访问数据源配置jsonData——明文。如果您启用了匿名访问,那么任何可以在浏览器中访问Grafana的人都可以看到jsonData只使用jsonData存储非敏感配置。

注意:通过输入,您可以看到当前用户有权访问的设置window.grafanaBootData在浏览器的开发人员控制台中。

注意:的用户Grafana企业可以限制特定用户和团队对数据源的访问。有关更多信息,请参阅数据源权限

如果您需要存储敏感信息,例如密码、令牌和API密钥,请使用secureJsonData代替。每当用户保存数据源配置时,其中的秘密secureJsonData被发送到Grafana服务器,并在存储之前进行加密。

一旦安全配置被加密,就不能再从浏览器访问它了。在秘密被保存后,唯一的方法就是使用数据源代理

向数据源插件添加秘密配置

为了演示如何向数据源插件添加密钥,让我们添加对配置API密钥的支持。

中创建一个新接口types.ts来保存API键。

导出接口MySecureJsonData {apiKey?:字符串;}

将类型信息添加到secureJsonData对象的ConfigEditor将接口作为第二个类型参数接受。

interface Props extends DataSourcePluginOptionsEditorProps {}

方法访问密匙的值选项道具在你的ConfigEditor直到用户保存配置。当用户保存配置时,Grafana会清除该值。之后,您可以使用secureJsonFields以确定是否已配置该属性。

const {secureJsonData, secureJsonFields} = options;const {apiKey} = secureJsonData;

要安全地更新插件配置编辑器中的秘密,请更新secureJsonData对象使用onOptionsChange道具。

const onAPIKeyChange = (event: ChangeEvent) => {onOptionsChange({…选项,secureJsonData: {apiKey: event.target。Value,},});};

接下来,定义一个可以接受用户输入的组件。

 .

最后,如果希望用户能够重置API键,则需要将属性设置为secureJsonFields对象。

const onResetAPIKey = () => {onOptionsChange({…secureJsonFields:{…options。secureJsonFields,apiKey:假,},secureJsonData:{ ...options.secureJsonData, apiKey: '', }, }); };

现在用户可以配置秘密了,下一步是看看如何将它们添加到请求中。

使用数据源代理进行身份验证

一旦用户保存了数据源的配置,浏览器中就不再有任何秘密的数据源配置了。加密的秘密只能在服务器上访问。那么如何将它们添加到请求中呢?

Grafana服务器提供了一个代理,允许您为请求定义模板。我们称之为代理航线.Grafana将代理路由发送到服务器,连同其他配置一起解密秘密,并在发送请求之前将它们添加到请求中。

注意:方法,确保不要将数据源代理与身份验证代理.数据源代理用于对数据源进行身份验证,而认证代理用于登录到Grafana本身。

在插件中添加代理路由

如果需要通过Grafana代理转发请求,需要配置一条或多条代理路由。代理路由是由代理处理的任何传出请求的模板。配置代理路由plugin.json文件。

  1. 将路由添加到plugin.json。注意,每次对插件进行更改时,都需要重新启动Grafana服务器。json文件。

    “路线”:[{“路径”:“例子”,“url”:“https://api.example.com”}]
  2. 数据源,从中提取代理URLinstanceSettings类属性url

    导出类DataSource extends DataSourceApi {url?:字符串;构造函数(instanceSettings: DataSourceInstanceSettings){超级(instanceSettings);这一点。url= instanceSettings.url; } // ... }
  3. 查询方法,使用BackendSrv.URL路径的第一部分需要匹配路径您的代理路由。替换数据源代理这一点。url+ routePathurl路线。以下请求将被提出给https://api.example.com/v1/users

    import {getBackendSrv} from '@grafana/runtime';
    const routePath = '/example';getBackendSrv()。datasourceRequest({url: this。url +路由路径+ '/v1/users', method: 'GET', });

为插件添加动态代理路由

Grafana将代理路由发送到服务器,数据源代理在服务器上解密任何敏感数据,并在发出请求之前将解密的数据插入模板变量。

如果要在路由中添加自定义配置,请使用add{{.JsonData。apiKey}}到路线,在哪里apiKey属性的名称是否在jsonData对象。

"routes": [{"path": "example", "url": "https://api.example.com/projects/{{. jsondata . "投影}}"}]

您还可以配置路由以使用敏感数据.SecureJsonData

“路线”:[{“路径”:“例子”,“url”:“https:// {{.JsonData。用户名}}:{{. securejsondata。密码}}@api.example.com"}]

除了URL之外,还可以向代理路由添加标头、URL参数和请求体。

为代理路由添加HTTP报头

"routes": [{"path": "example", "url": "https://api.example.com", "headers": [{"name": "Authorization", "content": " holder {{. securejsondata . "apiToken}}"}]}]

为代理路由添加URL参数

“路线”:[{“路径”:“例子”,“url”:“http://api.example.com”,“urlParams”:[{“名称”:“apiKey”,“内容”:“{{.SecureJsonData。apiKey}}"}]}]

添加请求体到代理路由

“路线”:[{“路径”:“例子”,“url”:“http://api.example.com”,“身体”:{“用户名”:“{{.JsonData。username}}", "password": "{{. securejsondata . "密码}}"}}]

在插件中添加OAuth 2.0代理路由

数据源代理支持OAuth 2.0身份验证。

由于对每个路由的请求都是在服务器端进行的,因此只支持机器对机器身份验证。换句话说,如果您需要使用不同于客户端凭证的授权,则需要自己实现它。

若要使用OAuth 2.0进行身份验证,请添加atokenAuth对象指定为代理路由定义。如有必要,Grafana会执行对中定义的URL的请求tokenAuth在向代理路由中的URL发出请求之前检索令牌。当令牌过期时,Grafana会自动更新令牌。

定义的任何参数tokenAuth.params编码为应用程序/ x-www-form-urlencoded并发送到令牌URL。

{"routes": [{"path": "api", "url": "https://api.example.com/v1", "tokenAuth": {"url": "https://api.example.com/v1/oauth/token", "params": {"grant_type": "client_credentials", "client_id": "{{. securejsondata . "clientId}}", "client_secret": "{{. securejsondata . "clientSecret}}"}}}]}

使用后端插件进行身份验证

虽然数据源代理支持HTTP api最常见的身份验证方法,但使用代理路由有一些限制:

  • 代理路由只支持HTTP和HTTPS协议
  • 代理路由不支持自定义令牌认证

如果这些限制适用于你的插件,你需要添加一个后端插件.由于后端插件运行在服务器上,它们可以访问解密的秘密,这使得更容易实现自定义身份验证方法。

解密的秘密可从DecryptedSecureJSONData字段。

function (ds *dataSource)Context, req *backend。QueryDataRequest) (*backend.QueryDataResponse, error) { instanceSettings := req.PluginContext.DataSourceInstanceSettings if apiKey, exists := settings.DecryptedSecureJSONData["apiKey"]; exists { // Use the decrypted API key. } // ... }

转发登录用户的OAuth标识

如果您的数据源使用与Grafana本身相同的OAuth提供者,例如使用通用OAuth身份验证,您的数据源插件可以为登录的Grafana用户重用访问令牌。

要允许Grafana将访问令牌传递给插件,请更新数据源配置并设置jsonData.oauthPassThru财产真正的.的DataSourceHttpSettings控件提供一个切换前向OAuth标识这个选项。您还可以构建一个适当的切换来设置jsonData.oauthPassThru在数据源配置页面UI中。

配置时,Grafana将在授权头中将用户的令牌传递给插件QueryDataRequest对象上的QueryData请求后端数据源。

function (ds *dataSource) CheckHealth(ctx上下文。Context, req *backend。CheckHealthRequest) (*backend.CheckHealthResult, error) { token := strings.Fields(req.Headers["Authorization"]) var ( tokenType = token[0] accessToken = token[1] ) // ... return &backend.CheckHealthResult{Status: backend.HealthStatusOk}, nil } func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { token := strings.Fields(req.Headers["Authorization"]) var ( tokenType = token[0] accessToken = token[1] ) for _, q := range req.Queries { // ... } }

此外,如果用户的令牌中包含ID令牌,Grafana将在插件中传递用户的ID令牌X-ID-Token头文件,可在QueryDataRequest对象上的QueryData请求后端数据源。

function (ds *dataSource) CheckHealth(ctx上下文。Context, req *backend。CheckHealthRequest) (*backend.CheckHealthResult, error) { idToken := req.Headers["X-ID-Token"] // ... return &backend.CheckHealthResult{Status: backend.HealthStatusOk}, nil } func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { idToken := req.Headers["X-ID-Token"] for _, q := range req.Queries { // ... } }

授权而且X-ID-Token的页眉也可用CallResourceRequest对象上的CallResource请求后端数据源时jsonData.oauthPassThru真正的

function (ds *dataSource) CallResource(ctx上下文)Context, req *backend。CallResourceRequest,sender backend.CallResourceResponseSender) error { token := req.Headers["Authorization"] idToken := req.Headers["X-ID-Token"] // present if user's token includes an ID token // ... }

注意:由于Grafana中的一个bug,在PostgreSQL中使用这个特性可能会导致死锁。有关更多信息,请参阅Grafana在PostgreSQL中导致死锁,而试图刷新用户令牌

为登录用户转发cookie

数据源插件可以为登录的Grafana用户转发某些cookie到数据源。使用DataSourceHttpSettings组件在数据源的配置页上。它提供允许饼干选项,其中可以指定要传递给插件的cookie的名称。

配置时,Grafana会将这些cookie传递给插件饼干头文件中可用QueryDataCallResource而且CheckHealth后端数据源中的请求。

function (ds *dataSource)Context, req *backend。QueryDataRequest) (*backend.QueryDataResponse, error) { cookies:= req.Headers["Cookie"] // ... } func (ds *dataSource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { cookies := req.Headers["Cookie"] // ... } func (ds *dataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { cookies:= req.Headers["Cookie"] // ... }