Aller au contenu

Microsoft Graph

De Banane Atomic

Liens

Description

Microsoft Graph remplace Office 365 API et Azure AD Graph API.
Il réunit au sein d'une unique API toutes les données relatives aux utilisateurs.

Web-hosted resource Application ID URI
The Office 365 Unified Mail API https://outlook.office.com
The Azure AD Graph API https://graph.windows.net
Microsoft Graph https://graph.microsoft.com

Permissions

Base url https://graph.microsoft.com/v1.0
L'erreur Access is denied. Check credentials and try again. signifie qu'il manque des permissions pour l'appel de la web API.
Description Url Permissions
Profil de l'utilisateur courant /me Pas de permission nécessaire,
fonctionne même sans l'ajout de l'API Microsoft Graph dans les permissions.
Liste des profils des utilisateurs /users Access directory as the signed in user
Photo
beta
/users/<userId>/photo/$value View users' basic profile
Read all users' basic profiles
Envoyer un email POST /me/sendMail Send mail as a user
Nécessite Outlook on the web (Exchange Web Connect, Outlook Web Access OWA)
Sinon erreur Resource could not be discovered
Événements du calendrier /me/events
/users/<userId>/events
Read user calendars
Accès aux configuration InTune
beta
/me/managedDevices Read Microsoft Intune apps (DeviceManagementApps.Read.All)

Converged vs Azure AD applications

Graph ne fonctionne qu'avec des Converged apps et pas avec des AAD apps.
Les Converged apps sont a enregistrer sur apps.dev.microsoft.com

Filtres sur les requêtes

Exemples
users?$filter=givenName eq 'Nicolas' and surname eq 'XXX')
users?$filter=startswith(givenName,'Nicolas')
me/events?$filter=start/dateTime ge '2009-06-15T13:45:30'
users?$top=999
users?$select=givenName,surname
me/events?$orderby=start/dateTime
Utiliser HttpUtility.UrlEncode pour encoder le contenu du filtre.

Video REST API

URL Description
https://xxx.sharepoint.com/portals/hub/_api/VideoService/Channels Liste des channels
https://xxx.sharepoint.com/portals/hub/_api/VideoService/Channels/(guid'xxx')/Videos(guid'xxx')/ThumbnailStream Thumbnail

Microsoft.Graph client library

  • package Nuget Microsoft.Graph
var graphClient = new GraphServiceClient(
        "https://graph.microsoft.com/v1.0",
        new DelegateAuthenticationProvider(
            async (requestMessage) =>
            {
                var token = TokenGraph;
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
                await Task.FromResult("");
            }));

// User Me
var user = await graphClient.Me.Request().GetAsync();
string userId = user.Id;

NextMeetingsForGraphSample

var start = DateTime.UtcNow.ToString("o");
var end = DateTime.UtcNow.AddDays(7).ToString("o");

var optionStart = new QueryOption("startDateTime", start);
var optionEnd = new QueryOption("endDateTime", end);

IUserCalendarViewCollectionPage calendarView = await graphService.Me.CalendarView.Request(new[] { optionStart, optionEnd }).GetAsync();

var hasMorePages = true;
var events = new List<Event>();
while (hasMorePages)
{
    foreach (var ev in calendarView.CurrentPage.ToList())
        events.Add(ev);
    hasMorePages = calendarView.NextPageRequest != null;
    if (hasMorePages)
        calendarView = await calendarView.NextPageRequest.GetAsync();
}

foreach (var ev in events) {}

WPF client

Avec un token Azure AD

MainWindows.xaml.cs
private string _clientId = "xxx";
private static string _tenant = "xxx.onmicrosoft.com";
private string _authority = $"https://login.microsoftonline.com/{_tenant}";

private string _graphResourceUrl = "https://graph.microsoft.com";
private string _resourceUrl = "https://xxx.onmicrosoft.com/xxx";

private Uri _redirectUri = new Uri("https://wpfclient");
string[] scopes = new string[] { "user.read" };

private HttpClient _httpClient = new HttpClient();
private string _token;
private string _tokenGraph;

private async void signin_Click(object sender, RoutedEventArgs e)
{
    AuthenticationContext authContext = new AuthenticationContext(_authority);
    AuthenticationResult authResult = null;

    try
    {
        authResult = await authContext.AcquireTokenAsync(_resourceUrl, _clientId, _redirectUri, new PlatformParameters(PromptBehavior.Auto));
        _token = authResult.AccessToken;
        AppendText("You signed in!");
    }
    catch (AdalException aex)
    {
        AppendText(aex.ToString());
    }
}

// get the token graph automatically if the azure AD is already in the cache
private async void tokengraph_Click(object sender, RoutedEventArgs e)
{
    AuthenticationContext authContext = new AuthenticationContext(_authority);
    AuthenticationResult authResult = null;

    try
    {
        authResult = await authContext.AcquireTokenSilentAsync(_graphResourceUrl, _clientId);
        _tokenGraph = authResult.AccessToken;
        AppendText("You got the token for the graph!");
    }
    catch (AdalException aex)
    {
        AppendText(aex.ToString());
    }
}

// use the token graph to request the graph
private async void profile_Click(object sender, RoutedEventArgs e)
{
    string url = "https://graph.microsoft.com/v1.0/me";

    if (_tokenGraph != null)
    {
        HttpResponseMessage response;
        try
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _tokenGraph);
            response = await _httpClient.SendAsync(request);
            var content = await response.Content.ReadAsStringAsync();
            AppendText(content);
        }
        catch (Exception ex)
        {
            AppendText(ex.ToString());
        }
    }
    else
    {
        AppendText("You need to get the token graph first.");
    }
}

Avec Microsoft.Identity.Client

Packages Nuget:

  • Microsoft.Identity.Client
MainWindows.xaml.cs
// config
// client ID de Converged applications.
// ne fonctionne pas avec les client ID des AAD applications
// AADSTS70001: Application is not supported for this API version.
private string _clientId = "xxx";
private static string _tenant = "xxx.onmicrosoft.com";
private string _authority = $"https://login.microsoftonline.com/{_tenant}";
// Set the scope for API call to user.read
string[] scopes = new string[] { "user.read" };

private PublicClientApplication _clientApp;
Microsoft.Identity.Client.AuthenticationResult authResult = null;
private HttpClient _httpClient = new HttpClient();

public MainWindow()
{
    InitializeComponent();
    _clientApp = new PublicClientApplication(_clientId, _authority, TokenCacheHelper.GetUserCache());
}

private async void signin_Click(object sender, RoutedEventArgs e)
{
    try
    {
        authResult = await _clientApp.AcquireTokenSilentAsync(scopes, _clientApp.Users.FirstOrDefault());
        AppendText("Signed-in using the cache.");
    }
    catch (MsalUiRequiredException ex)
    {
        try
        {
            authResult = await _clientApp.AcquireTokenAsync(scopes);
            AppendText("Signed-in successfully.");
        }
        catch (MsalException msalex)
        {
            AppendText($"Error Acquiring Token:\n{msalex}");
        }
    }
    catch (Exception ex)
    {
        AppendText($"Error Acquiring Token Silently:\n{ex}");
        return;
    }
}

private void signout_Click(object sender, RoutedEventArgs e)
{

}

private async void getProfile_Click(object sender, RoutedEventArgs e)
{
    //Set the API Endpoint to Graph 'me' endpoint
    string graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";

    if (authResult != null)
    {
        AppendText(await GetHttpContentWithToken(graphAPIEndpoint, authResult.AccessToken));
    }
    else
    {
        AppendText("You need to sign-in first.");
    }
}

/// <summary>
/// Perform an HTTP GET request to a URL using an HTTP Authorization header
/// </summary>
/// <param name="url">The URL</param>
/// <param name="token">The token</param>
/// <returns>String containing the results of the GET operation</returns>
public async Task<string> GetHttpContentWithToken(string url, string token)
{
    HttpResponseMessage response;
    try
    {
        var request = new HttpRequestMessage(HttpMethod.Get, url);
        // Add the token in Authorization header
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        response = await _httpClient.SendAsync(request);
        var content = await response.Content.ReadAsStringAsync();
        return content;
    }
    catch (Exception ex)
    {
        return ex.ToString();
    }
}
TokenCacheHelper.cs
static class TokenCacheHelper
{
    public static TokenCache GetUserCache()
    {
        if (usertokenCache == null)
        {
            usertokenCache = new TokenCache();
            usertokenCache.SetBeforeAccess(BeforeAccessNotification);
            usertokenCache.SetAfterAccess(AfterAccessNotification);
        }
        return usertokenCache;
    }

    static TokenCache usertokenCache;

    public static string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + "msalcache.txt";

    private static readonly object FileLock = new object();

    public static void BeforeAccessNotification(TokenCacheNotificationArgs args)
    {
        lock (FileLock)
        {
            args.TokenCache.Deserialize(File.Exists(CacheFilePath)
                ? File.ReadAllBytes(CacheFilePath)
                : null);
        }
    }

    public static void AfterAccessNotification(TokenCacheNotificationArgs args)
    {
        // if the access operation resulted in a cache update
        if (args.TokenCache.HasStateChanged)
        {
            lock (FileLock)
            {
                // reflect changes in the persistent store
                File.WriteAllBytes(CacheFilePath, args.TokenCache.Serialize());
                // once the write operation takes place restore the HasStateChanged bit to false
                args.TokenCache.HasStateChanged = false;
            }
        }
    }
}

Erreurs

Application is not supported for this API version.

  • Inscrire l'application comme converged app sur apps.dev.microsoft.com
  • Configurer l'app (redirect url)
  • Utiliser le client id de la converged app