Adicionar autenticação de utilizador às aplicações Go para o Microsoft Graph

Neste artigo, vai adicionar a autenticação de utilizador à aplicação que criou em Criar aplicações Go com o Microsoft Graph. Em seguida, utilize a API de utilizador do Microsoft Graph para obter o utilizador autenticado.

Adicionar autenticação de utilizador

O Módulo de Cliente de Identidade do Azure para Go fornece muitas TokenCredential classes que implementam fluxos de tokens OAuth2. O SDK do Microsoft Graph para Go utiliza essas classes para autenticar chamadas para o Microsoft Graph.

Configurar o cliente do Graph para autenticação de utilizador

Comece por utilizar a DeviceCodeCredential classe para pedir um token de acesso com o fluxo de código do dispositivo.

  1. Adicione a seguinte função a ./graphhelper/graphhelper.go.

    func (g *GraphHelper) InitializeGraphForUserAuth() error {
        clientId := os.Getenv("CLIENT_ID")
        tenantId := os.Getenv("TENANT_ID")
        scopes := os.Getenv("GRAPH_USER_SCOPES")
        g.graphUserScopes = strings.Split(scopes, ",")
    
        // Create the device code credential
        credential, err := azidentity.NewDeviceCodeCredential(&azidentity.DeviceCodeCredentialOptions{
            ClientID: clientId,
            TenantID: tenantId,
            UserPrompt: func(ctx context.Context, message azidentity.DeviceCodeMessage) error {
                fmt.Println(message.Message)
                return nil
            },
        })
        if err != nil {
            return err
        }
    
        g.deviceCodeCredential = credential
    
        // Create an auth provider using the credential
        authProvider, err := auth.NewAzureIdentityAuthenticationProviderWithScopes(credential, g.graphUserScopes)
        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.userClient = client
    
        return nil
    }
    

    Dica

    Se estiver a utilizar goimportso , alguns módulos poderão ser removidos da sua import instrução em graphhelper.go ao guardar. Poderá ter de adicionar os módulos novamente para criar.

  2. Substitua a função empty initializeGraph em graphtutorial.go pelo seguinte.

    func initializeGraph(graphHelper *graphhelper.GraphHelper) {
        err := graphHelper.InitializeGraphForUserAuth()
        if err != nil {
            log.Panicf("Error initializing Graph for user auth: %v\n", err)
        }
    }
    

Este código inicializa duas propriedades, um DeviceCodeCredential objeto e um GraphServiceClient objeto. A InitializeGraphForUserAuth função cria uma nova instância de DeviceCodeCredentiale, em seguida, utiliza essa instância para criar uma nova instância de GraphServiceClient. Sempre que é efetuada uma chamada à API ao Microsoft Graph através do userClient, utiliza a credencial fornecida para obter um token de acesso.

Testar o DeviceCodeCredential

Em seguida, adicione código para obter um token de acesso a DeviceCodeCredentialpartir do .

  1. Adicione a seguinte função a ./graphhelper/graphhelper.go.

    func (g *GraphHelper) GetUserToken() (*string, error) {
        token, err := g.deviceCodeCredential.GetToken(context.Background(), policy.TokenRequestOptions{
            Scopes: g.graphUserScopes,
        })
        if err != nil {
            return nil, err
        }
    
        return &token.Token, nil
    }
    
  2. Substitua a função empty displayAccessToken em graphtutorial.go pelo seguinte.

    func displayAccessToken(graphHelper *graphhelper.GraphHelper) {
        token, err := graphHelper.GetUserToken()
        if err != nil {
            log.Panicf("Error getting user token: %v\n", err)
        }
    
        fmt.Printf("User token: %s", *token)
        fmt.Println()
    }
    
  3. Crie e execute a aplicação ao executar go run graphtutorial. Introduza 1 quando lhe for pedida uma opção. A aplicação apresenta um URL e um código de dispositivo.

    Go Graph Tutorial
    
    Please choose one of the following options:
    0. Exit
    1. Display access token
    2. List my inbox
    3. Send mail
    4. Make a Graph call
    1
    To sign in, use a web browser to open the page https://microsoft.com/devicelogin and
    enter the code RB2RUD56D to authenticate.
    
  4. Abra um browser e navegue para o URL apresentado. Introduza o código fornecido e inicie sessão.

    Importante

    Tenha em atenção todas as contas existentes do Microsoft 365 com sessão iniciada no browser ao navegar para https://microsoft.com/devicelogino . Utilize funcionalidades do browser, como perfis, modo de convidado ou modo privado para garantir que se autentica como a conta que pretende utilizar para testes.

  5. Depois de concluído, regresse à aplicação para ver o token de acesso.

    Dica

    Apenas para fins de validação e depuração, pode descodificar tokens de acesso de utilizador (apenas para contas escolares ou profissionais) com o analisador de tokens online da Microsoft em https://jwt.ms. Analisar o token pode ser útil se encontrar erros de token ao chamar o Microsoft Graph. Por exemplo, verificar se a scp afirmação no token contém os âmbitos de permissão esperados do Microsoft Graph.

Obter usuário

Agora que a autenticação está configurada, pode fazer a sua primeira chamada do Microsoft API do Graph. Adicione código para obter o nome e o endereço de e-mail do utilizador autenticado.

  1. Adicione a seguinte função a ./graphhelper/graphhelper.go.

    func (g *GraphHelper) GetUser() (models.Userable, error) {
        query := users.UserItemRequestBuilderGetQueryParameters{
            // Only request specific properties
            Select: []string{"displayName", "mail", "userPrincipalName"},
        }
    
        return g.userClient.Me().Get(context.Background(),
            &users.UserItemRequestBuilderGetRequestConfiguration{
                QueryParameters: &query,
            })
    }
    
  2. Substitua a função empty greetUser em graphtutorial.go pelo seguinte.

    func greetUser(graphHelper *graphhelper.GraphHelper) {
        user, err := graphHelper.GetUser()
        if err != nil {
            log.Panicf("Error getting user: %v\n", err)
        }
    
        fmt.Printf("Hello, %s!\n", *user.GetDisplayName())
    
        // For Work/school accounts, email is in Mail property
        // Personal accounts, email is in UserPrincipalName
        email := user.GetMail()
        if email == nil {
            email = user.GetUserPrincipalName()
        }
    
        fmt.Printf("Email: %s\n", *email)
        fmt.Println()
    }
    

Se executar a aplicação agora, depois de iniciar sessão na aplicação dá-lhe as boas-vindas pelo nome.

Hello, Megan Bowen!
Email: MeganB@contoso.com

Código explicado

Considere o código na getUser função . São apenas algumas linhas, mas há alguns detalhes importantes a notar.

Aceder a 'eu'

A função utiliza o userClient.Me construtor de pedidos, que cria um pedido para a API Obter utilizador . Esta API está acessível de duas formas:

GET /me
GET /users/{user-id}

Neste caso, o código chama o ponto final da GET /me API. Este ponto final é um método de atalho para obter o utilizador autenticado sem saber o respetivo ID de utilizador.

Observação

Uma vez que o GET /me ponto final da API obtém o utilizador autenticado, só está disponível para aplicações que utilizam autenticação de utilizador. As aplicações de autenticação apenas de aplicações não podem aceder a este ponto final.

Pedir propriedades específicas

A função utiliza a Select propriedade nos parâmetros de consulta do pedido para especificar o conjunto de propriedades de que precisa. Esta propriedade adiciona o parâmetro de consulta $select à chamada à API.

Tipo de retorno fortemente escrito

A função devolve um Userable objeto serializado da resposta JSON da API. Uma vez que o código utiliza Select, apenas as propriedades pedidas têm valores no objeto devolvido Userable . Todas as outras propriedades têm valores predefinidos.

Próxima etapa