使用 Microsoft Graph 和仅限应用的身份验证生成 Go 应用
本教程介绍如何生成 Go 控制台应用,该应用使用 Microsoft Graph API 使用仅应用身份验证访问数据。 对于需要访问组织中所有用户的数据的后台服务或应用程序,仅应用身份验证是一个不错的选择。
注意
若要了解如何使用 Microsoft Graph 代表用户访问数据,请参阅此 用户 (委托) 身份验证教程。
在本教程中,你将:
提示
作为本教程的替代方法,可以下载或克隆 GitHub 存储库 ,并按照 README 中的说明注册应用程序并配置项目。
先决条件
在开始本教程之前,应在开发计算机上安装 Go 。
还应具有具有全局管理员角色的Microsoft工作或学校帐户。 如果没有 Microsoft 365 租户,则可以通过 Microsoft 365 开发人员计划获得租户;有关详细信息,请参阅 常见问题解答。 或者,可以 注册 1 个月的免费试用版或购买 Microsoft 365 计划。
注意
本教程使用 Go 版本 1.19.3 编写。 本指南中的步骤可能适用于其他版本,但尚未测试。
在门户中注册该应用
在本练习中,你将在 Azure Active Directory 中注册一个新应用程序,以启用 仅限应用的身份验证。 可以使用 Microsoft Entra 管理中心或使用 Microsoft Graph PowerShell SDK 注册应用程序。
注册应用程序进行仅限应用的身份验证
在本部分中,你将使用 客户端凭据流注册支持仅限应用身份验证的应用程序。
打开浏览器,导航到 Microsoft Entra 管理中心 ,并使用全局管理员帐户登录。
在左侧导航栏中选择“Microsoft Entra ID”,依次展开“标识”、“应用程序”和“应用注册”。
选择“新注册”。 输入应用程序的名称,例如
Graph App-Only Auth Tutorial
。将 “支持的帐户类型 ”设置为 “仅此组织目录中的帐户”。
保留“重定向 URI”为空。
选择“注册”。 在应用程序的 “概述 ”页上,复制 “应用程序 (客户端) ID ”和 “目录 (租户) ID ”的值并保存它们,下一步将需要这些值。
在“管理”下选择 “API 权限”。
删除“配置权限”下的默认 User.Read 权限,方法是在其行中选择省略号 (...) 并选择“删除权限”。
选择“ 添加权限”,然后选择 “Microsoft Graph”。
选择“应用程序权限”。
选择 “User.Read.All”,然后选择“ 添加权限”。
选择“ 授予管理员同意...”,然后选择“ 是 ”,为所选权限提供管理员同意。
选择“管理”下的“证书和机密”,然后选择“新建客户端密码”。
输入说明,选择持续时间,然后选择 “添加”。
复制 “值 ”列中的机密,后续步骤中将需要它。
重要
此客户端密码不会再次显示,所以请务必现在就复制它。
注意
请注意,与注册用户身份验证时的步骤不同,在本部分中,你配置了对应用注册Microsoft Graph 权限。 这是因为仅应用身份验证使用 客户端凭据流,这需要在应用注册上配置权限。 有关详细信息 ,请参阅 .default 范围 。
创建 Go 控制台应用
首先使用 Go CLI 初始化新的 Go 模块。 在要在其中创建项目的目录中打开命令行界面 (CLI) 。 运行以下命令:
go mod init graphapponlytutorial
安装依赖项
在继续操作之前,请添加稍后将使用的一些其他依赖项。
- 适用于 Go 的 Azure 标识客户端模块 ,用于对用户进行身份验证并获取访问令牌。
- Microsoft Graph SDK for Go 调用 Microsoft Graph。
- 用于从 .env 文件读取环境变量的 GoDotEnv。
在 CLI 中运行以下命令以安装依赖项。
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity
go get github.com/microsoftgraph/msgraph-sdk-go
go get github.com/joho/godotenv
加载应用程序设置
在本部分中,你将向项目添加应用注册的详细信息。
在 go.mod 的同一目录中创建名为 .env 的文件,并添加以下代码。
CLIENT_ID=YOUR_CLIENT_ID_HERE CLIENT_SECRET=YOUR_CLIENT_SECRET_HERE TENANT_ID=YOUR_TENANT_ID_HERE
根据下表更新值。
设置 值 CLIENT_ID
应用注册的客户端 ID CLIENT_SECRET
应用注册的客户端密码 TENANT_ID
组织的租户 ID 提示
(可选)可以在名为 .env.local 的单独文件中设置这些值。
设计应用
在本部分中,你将创建一个基于控制台的简单菜单。
在 与 go.mod 相同的目录中创建名为 graphhelper 的新目录。
在 graphhelper 目录中添加名为 graphhelper.go 的新文件,并添加以下代码。
package graphhelper import ( "context" "os" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" auth "github.com/microsoft/kiota-authentication-azure-go" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/microsoftgraph/msgraph-sdk-go/users" ) type GraphHelper struct { clientSecretCredential *azidentity.ClientSecretCredential appClient *msgraphsdk.GraphServiceClient } func NewGraphHelper() *GraphHelper { g := &GraphHelper{} return g }
这将创建一个基本 GraphHelper 类型,稍后将扩展该类型以使用 Microsoft Graph。
在 go.mod 的同一目录中创建名为 graphapponlytutorial.go 的文件。 添加以下代码。
package main import ( "fmt" "graphapponlytutorial/graphhelper" "log" "github.com/joho/godotenv" ) func main() { fmt.Println("Go Graph App-Only Tutorial") fmt.Println() // Load .env files // .env.local takes precedence (if present) godotenv.Load(".env.local") err := godotenv.Load() if err != nil { log.Fatal("Error loading .env") } graphHelper := graphhelper.NewGraphHelper() initializeGraph(graphHelper) var choice int64 = -1 for { fmt.Println("Please choose one of the following options:") fmt.Println("0. Exit") fmt.Println("1. Display access token") fmt.Println("2. List users") fmt.Println("3. Make a Graph call") _, err = fmt.Scanf("%d", &choice) if err != nil { choice = -1 } switch choice { case 0: // Exit the program fmt.Println("Goodbye...") case 1: // Display access token displayAccessToken(graphHelper) case 2: // List users listUsers(graphHelper) case 3: // Run any Graph code makeGraphCall(graphHelper) default: fmt.Println("Invalid choice! Please try again.") } if choice == 0 { break } } }
在文件末尾添加以下占位符方法。 你将在后面的步骤中实现它们。
func initializeGraph(graphHelper *graphhelper.GraphHelper) { // TODO } func displayAccessToken(graphHelper *graphhelper.GraphHelper) { // TODO } func listUsers(graphHelper *graphhelper.GraphHelper) { // TODO } func makeGraphCall(graphHelper *graphhelper.GraphHelper) { // TODO }
这将实现基本菜单,并从命令行读取用户的选择。
添加仅限应用的身份验证
在本部分中,将向应用程序添加仅限应用的身份验证。 需要 获取必要的 OAuth 访问令牌才能调用 Microsoft Graph。 在此步骤中,你将 将适用于 Go 的 Azure 标识客户端模块 集成到应用程序中,并为 Microsoft Graph SDK for Go 配置身份验证。
Azure 标识库提供了许多 TokenCredential
实现 OAuth2 令牌流的类。 Microsoft Graph SDK 使用这些类对 Microsoft Graph 的调用进行身份验证。
为 Graph 客户端配置仅限应用的身份验证
在本部分中, ClientSecretCredential
你将使用 类通过 客户端凭据流请求访问令牌。
将以下函数添加到 ./graphhelper/graphhelper.go。
func (g *GraphHelper) InitializeGraphForAppAuth() error { clientId := os.Getenv("CLIENT_ID") tenantId := os.Getenv("TENANT_ID") clientSecret := os.Getenv("CLIENT_SECRET") credential, err := azidentity.NewClientSecretCredential(tenantId, clientId, clientSecret, nil) if err != nil { return err } g.clientSecretCredential = credential // Create an auth provider using the credential authProvider, err := auth.NewAzureIdentityAuthenticationProviderWithScopes(g.clientSecretCredential, []string{ "https://graph.microsoft.com/.default", }) if err != nil { return err } // Create a request adapter using the auth provider adapter, err := msgraphsdk.NewGraphRequestAdapter(authProvider) if err != nil { return err } // Create a Graph client using request adapter client := msgraphsdk.NewGraphServiceClient(adapter) g.appClient = client return nil }
提示
如果使用 goimports,则在保存时,某些模块可能已从
import
graphhelper.go 中的语句中自动删除。 可能需要重新添加要生成的模块。将 graphapponlytutorial.go 中的空
initializeGraph
函数替换为以下内容。func initializeGraph(graphHelper *graphhelper.GraphHelper) { err := graphHelper.InitializeGraphForAppAuth() if err != nil { log.Panicf("Error initializing Graph for app auth: %v\n", err) } }
此代码初始化两个 DeviceCodeCredential
属性:对象和 GraphServiceClient
对象。 函数 InitializeGraphForUserAuth
创建 的新实例 DeviceCodeCredential
,然后使用该实例创建 的新 GraphServiceClient
实例。 每次通过 userClient
进行 API 调用以Microsoft Graph 时,都会使用提供的凭据来获取访问令牌。
测试 ClientSecretCredential
接下来,添加代码以从 ClientSecretCredential
获取访问令牌。
将以下函数添加到 ./graphhelper/graphhelper.go。
func (g *GraphHelper) GetAppToken() (*string, error) { token, err := g.clientSecretCredential.GetToken(context.Background(), policy.TokenRequestOptions{ Scopes: []string{ "https://graph.microsoft.com/.default", }, }) if err != nil { return nil, err } return &token.Token, nil }
将 graphapponlytutorial.go 中的空
displayAccessToken
函数替换为以下内容。func displayAccessToken(graphHelper *graphhelper.GraphHelper) { token, err := graphHelper.GetAppToken() if err != nil { log.Panicf("Error getting user token: %v\n", err) } fmt.Printf("App-only token: %s", *token) fmt.Println() }
通过运行 生成并运行
go run graphapponlytutorial
应用。 当系统提示输入选项时,请输入1
。 应用程序显示访问令牌。Go Graph App-Only Tutorial Please choose one of the following options: 0. Exit 1. Display access token 2. List users 3. Make a Graph call 1 App-only token: eyJ0eXAiOiJKV1QiLCJub25jZSI6IlVDTzRYOWtKYlNLVjVkRzJGenJqd2xvVUcwWS...
提示
仅出于验证和调试目的,可以使用 Microsoft 的联机令牌分析器在 中https://jwt.ms解码仅限应用的访问令牌。 如果在调用 Microsoft Graph 时遇到令牌错误,这很有用。 例如,验证令牌中的声明是否
role
包含预期的 Microsoft Graph 权限范围。
列出用户
在本部分中,你将添加使用仅限应用的身份验证列出 Azure Active Directory 中的所有用户的功能。
将以下函数添加到 ./graphhelper/graphhelper.go。
func (g *GraphHelper) GetUsers() (models.UserCollectionResponseable, error) { var topValue int32 = 25 query := users.UsersRequestBuilderGetQueryParameters{ // Only request specific properties Select: []string{"displayName", "id", "mail"}, // Get at most 25 results Top: &topValue, // Sort by display name Orderby: []string{"displayName"}, } return g.appClient.Users(). Get(context.Background(), &users.UsersRequestBuilderGetRequestConfiguration{ QueryParameters: &query, }) }
将 graphapponlytutorial.go 中的空
listUsers
函数替换为以下内容。func listUsers(graphHelper *graphhelper.GraphHelper) { users, err := graphHelper.GetUsers() if err != nil { log.Panicf("Error getting users: %v", err) } // Output each user's details for _, user := range users.GetValue() { fmt.Printf("User: %s\n", *user.GetDisplayName()) fmt.Printf(" ID: %s\n", *user.GetId()) noEmail := "NO EMAIL" email := user.GetMail() if email == nil { email = &noEmail } fmt.Printf(" Email: %s\n", *email) } // If GetOdataNextLink does not return nil, // there are more users available on the server nextLink := users.GetOdataNextLink() fmt.Println() fmt.Printf("More users available? %t\n", nextLink != nil) fmt.Println() }
运行应用,登录并选择选项 2 列出用户。
Please choose one of the following options: 0. Exit 1. Display access token 2. List users 3. Make a Graph call 2 User: Adele Vance ID: 05fb57bf-2653-4396-846d-2f210a91d9cf Email: AdeleV@contoso.com User: Alex Wilber ID: a36fe267-a437-4d24-b39e-7344774d606c Email: AlexW@contoso.com User: Allan Deyoung ID: 54cebbaa-2c56-47ec-b878-c8ff309746b0 Email: AllanD@contoso.com User: Bianca Pisani ID: 9a7dcbd0-72f0-48a9-a9fa-03cd46641d49 Email: NO EMAIL User: Brian Johnson (TAILSPIN) ID: a8989e40-be57-4c2e-bf0b-7cdc471e9cc4 Email: BrianJ@contoso.com ... More users available? true
代码说明
请考虑 函数中的 GetUsers
代码。
- 它获取用户的集合
- 它使用
Select
请求特定属性 - 它使用
Top
来限制返回的用户数 - 它使用
OrderBy
对响应进行排序
可选:添加自己的代码
在本部分中,将向应用程序添加自己的 Microsoft Graph 功能。 这可能是Microsoft Graph 文档 或 Graph 资源管理器中的代码片段,也可以是你创建的代码片段。 此部分是可选的。
更新应用
将以下函数添加到 ./graphhelper/graphhelper.go。
func (g *GraphHelper) MakeGraphCall() error { // INSERT YOUR CODE HERE return nil }
将 graphapponlytutorial.go 中的空
makeGraphCall
函数替换为以下内容。func makeGraphCall(graphHelper *graphhelper.GraphHelper) { err := graphHelper.MakeGraphCall() if err != nil { log.Panicf("Error making Graph call: %v", err) } }
选择 API
在 Microsoft Graph 中查找想要尝试的 API。 例如, 创建事件 API。 可以使用 API 文档中的示例之一,也可以在 Graph 资源管理器中自定义 API 请求并使用生成的代码片段。
配置权限
查看所选 API 的参考文档 的“权限” 部分,了解支持哪些身份验证方法。 例如,某些 API 不支持仅限应用或个人Microsoft帐户。
- 若要调用具有用户身份验证 (API(如果 API 支持用户 (委托) 身份验证) ),请参阅 用户 (委托) 身份验证 教程。
- 若要调用具有仅应用身份验证 (API(如果 API 支持) ),请在 Azure AD 管理中心中添加所需的权限范围。
添加代码
将代码复制到 MakeGraphCall
graphhelper.go 中的函数中。 如果要从文档或 Graph 资源管理器复制代码片段,请务必将 重命名 GraphServiceClient
为 appClient
。
恭喜!
你已完成 Go Microsoft Graph 教程。 现在,你已有一个可调用 Microsoft Graph 的工作应用,可以试验和添加新功能。
- 了解如何通过 Microsoft Graph Go SDK 使用 用户 (委托) 身份验证 。
- 访问 Microsoft Graph 概述 ,查看可以使用 Microsoft Graph 访问的所有数据。
你有关于此部分的问题? 如果有,请向我们提供反馈,以便我们对此部分作出改进。