【问题标题】:MS Graph - Getting App Token (Console Application)MS Graph - 获取应用程序令牌(控制台应用程序)
【发布时间】:2017-11-06 21:07:10
【问题描述】:
  • 控制台应用程序 - C# .Net 4.6
  • 专用管理员用户 - 我不能每次都提示登录 - 必须作为本机命令行/控制台应用程序在无人参与的情况下运行。

我只是试图让不记名令牌与 Graph SDK 调用一起发送。 我得到了一个令牌 (每次都是同一个),但被告知它已过期。这是消息:

访问令牌已过期,请使用访问令牌和刷新令牌进行验证

由于这是一个控制台应用程序,我不知道如何获取/保留访问和刷新令牌来执行此操作。

仅供参考:我之前的努力是按照以下步骤进行的

这是我最近的努力。欢迎任何帮助:

using Microsoft.Graph;
using Microsoft.Identity.Client;

public static async Task<string> GetTokenForAppAsync()
{
    if (TokenForApplication == null || TokenForApplicationExpiration <= DateTimeOffset.UtcNow.AddMinutes(5))
    {
        TokenCacheUser = null;
        TokenCacheApplication = null;

        ConfidentialClientApplication cl = new ConfidentialClientApplication(Settings.AuthClientId,
            returnUrl,
            new ClientCredential(Settings.AuthClientSecret),
            TokenCacheUser,
            TokenCacheApplication);

        AuthenticationResult authResult = cl.AcquireTokenForClientAsync(new string[] { "https://graph.microsoft.com/.default" }, true).Result;
        TokenForApplication = authResult.AccessToken;
        Console.WriteLine(authResult.AccessToken);
    }
    return TokenForApplication;
}

我对任何利用 MS Graph 和 Identity Libs 的解决方案持开放态度。

【问题讨论】:

  • 你找到解决这个问题的方法了吗?
  • 我做了,我会看看我是否可以发布一些代码..
  • @stackoverflow.com/users/5876732/niels - 请参阅下面的答案,希望对您有所帮助,并感谢您提醒跟进此问题

标签: microsoft-graph-api


【解决方案1】:

graph_authentication_example

这是控制台应用程序基于令牌的身份验证示例。应用程序必须至少运行一次,系统会提示您登录,但一旦完成,身份验证令牌就会存储在运行应用程序的机器上。

我从我们的服务器运行控制台应用程序作为任务并访问 Graph API 以使用 Graph Endpoints 获取各种 ActiveDirectory 数据集 - 通常我需要在发布后登录,然后再运行 - 这只是在测试阶段现在但似乎运作良好。

依赖关系:

  • 必须有一个 Azure Active Directory 用户,用于登录和后续身份验证。一切都发生在这个用户的上下文中。
  • 使用以下 Nuget 包:
    • Microsoft.Graph >= v1.6.2
    • Microsoft.Graph.Core >= v1.6.2
    • Microsoft.Identity.Client >= v1.1.0 预览版
    • Microsoft.IdentityModel.Clients.ActiveDirectory >= v3.17.1
    • Newtonsoft.Json >= v1.0.3
    • System.Net.Http >= v4.3.3
    • System.Security.Cryptography.Algorithms >= v4.3.0
    • System.Security.Cryptography.Encoding >= v4.3.0
    • System.Security.Cryptography.Primitives >= v4.3.0
  • 您必须在此处创建一个应用程序 [https://apps.dev.microsoft.com/] 在上面创建的同一用户下,这将为您提供您的客户端/应用程序 ID。
  • 您可以在此处查看 Graph [https://developer.microsoft.com/en-us/graph/graph-explorer/] 并使用上面创建的用户登录以针对您自己的 Azure Active Directory 进行测试。

设置

我使用 .ini 文件来存储设置,但值是有效的,.ini 样式的 cmets - 请注意,某些条目中有 {name} 样式文本,用于字符串替换。

您将看到 Settings.SomeName - 映射到以下内容:

[Endpoint] ; we don't want v1.0 because of our needs but it is valid GraphVersion = beta ; v1.0 or beta ; Common Graph endpoint - we sub version GraphEndpoint = https://graph.microsoft.com/{version} [Auth] ; authentication uri Uri = https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token ; authority uri Authority = https://login.microsoftonline.com/{tenant} ; if we need to login or re-login RedirectUri = https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient ; you may have a GUID style tenant but 'common' worked fine since it auth's back to Azure anyway Tenant = common ; the scopes we needed with Graph, yours may vary Scopes = { User.ReadBasic.All, User.Read.All, User.ReadWrite.All, Directory.AccessAsUser.All, Directory.Read.All, Directory.ReadWrite.All, Group.ReadWrite.All } ; the id of your azure application - guid ClientId = xxxx###-2##8-4##9-b##1-ec#########8f2 GrantType = client_credentials

代码片段

我试图包含完整的函数并通过指出它们来自哪些文件来表示分离。这些是令牌身份验证的主要部分 - 大部分是完整的代码,但“私有”代码除外。

起点:假设在我的 Program.cs 中,我调用了以下函数,一切都从这里流出以进行身份​​验证:

// we are just getting a group by id - CreateAuthenticatedClient() is called before every call to Graph
public static async Task<Group> GetGroupAsync(string groupId)
{
    var graphClient = AuthenticationHelper.CreateAuthenticatedClient();

    try
    {
        var group = await graphClient.Groups[groupId].Request().GetAsync();
        if (group == null) return null;
        return group;
    }
    catch (ServiceException e)
    {
        ConsoleHelper.WriteException($"GetGroupAsync.{ServiceErrorString(e)}");
        return null;
    }
}

AuthenticationHelper.cs - 完整类

public class AuthenticationHelper
{
    public static string TokenForUser = null;
    public static DateTimeOffset TokenForUserExpiration;

    // this is the 'magic' where we get the user cache
    public static PublicClientApplication IdentityClientApp = new PublicClientApplication(Settings.AuthClientId, Settings.AuthAuthority, TokenCacheHelper.GetUserCache());

    private static GraphServiceClient graphClient = null;

    // Get an access token for the given context and resourceId. An attempt is first made to 
    // acquire the token silently. If that fails, then we try to acquire the token by prompting the user.
    public static GraphServiceClient CreateAuthenticatedClient()
    {
        if (graphClient == null)
        {
            try
            {
                graphClient = new GraphServiceClient(
                    Settings.GraphEndpoint,
                    new DelegateAuthenticationProvider(
                        async (requestMessage) =>
                        {
                            var token = await GetTokenForUserAsync();
                            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
                            requestMessage.Headers.Add("azure-graph-test", "manage group membership");
                        }));
                return graphClient;
            }

            catch (ServiceException sex)
            {
                Console.WriteLine($"Could not create a graph client service: {sex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Could not create a graph client: {ex.Message}");
            }
        }
        return graphClient;
    }

    /// <summary>
    ///     get Token for User
    /// </summary>
    public static async Task<string> GetTokenForUserAsync()
    {
        if (TokenForUser == null || TokenForUserExpiration <= DateTimeOffset.UtcNow.AddMinutes(5))
        {
            AuthenticationResult authResult;
            try
            {
                authResult = await IdentityClientApp.AcquireTokenSilentAsync(Settings.AuthScopes, IdentityClientApp.Users.FirstOrDefault());
                TokenForUser = authResult.AccessToken;
            }
            catch (Exception)
            {
                if (TokenForUser == null || TokenForUserExpiration <= DateTimeOffset.UtcNow.AddMinutes(5))
                {
                    authResult = await IdentityClientApp.AcquireTokenAsync(Settings.AuthScopes);
                    TokenForUser = authResult.AccessToken;
                    TokenForUserExpiration = authResult.ExpiresOn;
                }
            }
        }

        return TokenForUser;
    }
}

TokenCacheHelper.cs - 这是一个 microsoft 类,它是获取/设置令牌缓存的关键

// Copyright (c) Microsoft Corporation.
// All rights reserved.
// This code is licensed under the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

static class TokenCacheHelper
{

    /// <summary>
    /// Get the user token cache
    /// </summary>
    public static TokenCache GetUserCache()
    {
        if (usertokenCache == null)
        {
            usertokenCache = new TokenCache();
            usertokenCache.SetBeforeAccess(BeforeAccessNotification);
            usertokenCache.SetAfterAccess(AfterAccessNotification);
        }
        return usertokenCache;
    }

    static TokenCache usertokenCache;

    /// <summary>
    /// Path to the token cache
    /// </summary>
    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 operationtakes place restore the HasStateChanged bit to filse
                args.TokenCache.HasStateChanged = false;
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-20
    • 2020-05-27
    • 2016-07-17
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    相关资源
    最近更新 更多