我只是想让持有者令牌与Graph SDK调用一起发送。 我收到了一个令牌 (每次都是同一个人),但我被告知已经过期了。以下是信息:
访问令牌已过期,请使用Access&刷新令牌以验证
由于这是一个控制台应用程序,我不知道如何获取/保持访问权限并刷新令牌来执行此操作。
仅供参考:早些时候我按照无用户访问的步骤进行了工作:https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service我无法通过该页面上的简单令牌HTTP请求:未经授权。
这是我最近的努力。欢迎任何帮助:
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的任何解决方案持开放态度。
答案 0 :(得分:0)
这是控制台应用程序基于令牌的身份验证的示例。应用程序必须至少运行一次,系统将提示您登录,但一旦完成,将在运行应用程序的计算机上存储身份验证令牌。
我从我们的服务器运行一个控制台应用程序作为任务,并使用Graph端点访问Graph API以获取各种ActiveDirectory数据集 - 通常我需要在发布后登录然后再运行 - 这是在测试阶段现在但似乎运作良好。
我使用.ini文件存储设置,但值是有效的,.ini样式的注释 - 请注意某些条目中有{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 - 这是获取/设置令牌缓存的关键的微软类
// 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;
}
}
}
}