当前位置: 首页 > 知识库问答 >
问题:

如何在不使用会话的情况下获取图令牌?

锺离旻
2023-03-14

我有一个正在使用Azure AD身份验证的应用程序。我还需要访问Microsoft Graph API以获取用户数据。我发现的每个向Graph API发出请求的示例都使用了缓存的会话令牌,但由于我使用的是JWT,因此显然不需要存储会话状态。如何使用JWT将我的应用程序作为受众来获得具有适当受众的JWT?

例如,这里有一个从Microsoft Graph AspNetCore示例检索令牌的请求:

_userTokenCache = new SessionTokenCache(userId, _memoryCache).GetCacheInstance();

var cca = new ConfidentialClientApplication(
    _appId,
    _redirectUri,
    _credential,
    _userTokenCache,
    null);
var result = await cca.AcquireTokenSilentAsync(_scopes, cca.Users.First());
return result.AccessToken;

它利用内存缓存从使用OpenId Connect cookie的Challenge()重定向登录中提取令牌。但是,由于我使用的是JWT,我已经有了一个不记名令牌,但权限错误。我需要做些什么来获取一个可以用来访问Graph API的新令牌?我仍然希望令牌对我的应用程序ID进行授权,所以我想要一个新令牌,允许我通过服务器端Rest请求访问API。

编辑:错误地标记为 Azure AD 图形,重新标记为微软图形。

编辑编辑:为了澄清,到目前为止,我看到的每个示例都在使用会话cookie:

services.AddAuthentication(sharedOptions => {
        sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddAzureAd(options => Configuration.Bind("AzureAd", options))
    .AddCookie();

但是,我使用的是JWT,所以没有缓存令牌:

app.UseJwtBearerAuthentication(new JwtBearerOptions {
    Authority = $"{instance}{tenant}",
        Audience = audience,
        SaveToken = true
});

我从对login.microsoftonline.com的请求中获得的JWT将我的应用程序作为受众,而这些示例生成的JWT将https://graph.microsoft.com作为受众。所以我需要(我认为至少)仅使用我从标准身份验证请求中获得的令牌为这些受众获取令牌。

共有1个答案

权黎昕
2023-03-14

不要将如何管理令牌(即令牌缓存)与令牌本身混淆。缓存令牌的原因很简单,您可以根据需要请求刷新令牌(refresh_token)。刷新令牌仅为某些sceanios提供(即,当使用<code>authorization_code</code>流时,您已请求<code>离线访问</code>范围)。

如果使用的是没有刷新令牌(即隐式client_credentials)的流,则可能不需要缓存令牌。通常仍应缓存它们,因为从 AAD 获取令牌会产生开销成本,并且缓存只允许在现有令牌过期时检索新令牌。

使用委托身份验证提供程序与现有令牌

尽管如此,听起来你已经有了一个令牌。由于MSAL(这也是< code > confidential client application 的来源)的全部目的是为您检索和管理令牌,我不太确定您为什么要这样做。我会简单地跳过MSAL完全只使用您现有的令牌。

如果你用的是微软的图表。您可以完全删除MSAL,只需通过< code > DelegateAuthenticationProvider 使用您现有的令牌(< code>access_token):

var graphServiceClient = new GraphServiceClient(
    new DelegateAuthenticationProvider((requestMessage) => {
        requestMessage.Headers.Authorization =
            new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token.access_token);

        return Task.FromResult(0);
    })
);

至于“适当的观众”,我不确定我理解了上下文。您的令牌将需要包括Microsoft Graph的范围,但是您如何定义它们取决于您如何获得令牌。

v1 终结点

如果使用较旧的Azure AD OAUTH终结点(又称v1终结点),则需要通过Azure门户配置应用程序权限。为了在不同的API(称为资源)之间切换,您需要请求offline_access并使用refresh_token。切换涉及在传入新的资源时请求刷新的令牌。然后生成的令牌将使用该资源。

例如,如果我的默认资源是SharePoint Online实例(https://tenant.sharepoint.com),那么我通常会使用如下内容刷新我的令牌:

private async Task<string> RequestTokenAsync() {
    var data = new Dictionary<string, string>();
    data.Add("grant_type", "refresh_token");
    data.Add("client_id", _clientId);
    data.Add("client_secret", _clientSecret);
    data.Add("resource", "https://tenant.sharepoint.com");
    data.Add("redirect_uri", RedirectUri);
    data.Add("refresh_token ", refresh_token);

    HttpClient httpClient = new HttpClient();
    var response = await httpClient.PostAsync(_tokenUri, new FormUrlEncodedContent(data));
    response.EnsureSuccessStatusCode();
    var result = await result.Content.ReadAsStringAsync();
}

现在,如果我想调用微软图形,我首先需要获取 https://graph.microsoft.com 资源的令牌:

private async Task<string> RequestTokenAsync() {
    var data = new Dictionary<string, string>();
    data.Add("grant_type", "refresh_token");
    data.Add("client_id", _clientId);
    data.Add("client_secret", _clientSecret);
    data.Add("resource", "https://graph.microsoft.com");
    data.Add("redirect_uri", RedirectUri);
    data.Add("refresh_token ", refresh_token);

    HttpClient httpClient = new HttpClient();
    var response = await httpClient.PostAsync(_tokenUri, new FormUrlEncodedContent(data));
    response.EnsureSuccessStatusCode();
    var result = await result.Content.ReadAsStringAsync();
}

现在我有两个令牌,一个用于SharePoint,一个用于Microsoft Graph。我可以通过简单地刷新适当资源的令牌来在资源之间切换。但是,我必须确保我正确刷新,因为如果我的refresh_token在我可以替换它之前过期,我就完全丢失了我的凭据。

如果这听起来很复杂,那确实如此。通常,您需要构建一些机制来管理哪些令牌处于活动状态,哪些令牌需要替换等。这就是令牌缓存的全部内容,因为 MSAL/ADAL 会为您处理此问题。

v2 终结点

较新的v2endpoint更容易使用。它使用< code >范围,而不是< code >资源。这些范围包括资源标识符,可以根据需要动态分配。

因此,虽然在v1中我们可能从Microsoft Graph分配< code>user.read和从Outlook Rest API分配< code>user.read,但我们现在可以通过同时请求< code > https://Graph . Microsoft . com/user . read 和< code > https://Outlook . office . com/user . read 在单个令牌中同时分配这两者。这意味着我们获得了一个可以与任一API一起使用的单一令牌,而无需从上面进入“更新以切换资源”的业务。

v2的缺点是目前只有有限数量的API支持它。如果您需要跨多个API工作,出于这个原因,使用v1可能更好。

希望这能有点帮助。

 类似资料:
  • 当我使用自己的客户端id在浏览器中转到以下URL时: https://account-d.docusign.com/oauth/auth?response_type=token 我需要登录,然后我被重定向到:http://localhost:8888/auth#access_token=myAccessToken 现在我有一个节点。在js应用程序中,我想使用我的访问令牌进行API调用,直到现在,我

  • 首先,如果这是一个很长的代码段,我很抱歉,但是,我想做一个模态窗口,它将你在我的用户表单中写的东西写下来,并要求你确认它。我目前正在学习Javascript,我不允许使用innerHTML,我必须动态地编写“名字”等(名字的文本),不允许只在弹出窗口内写它。我已经让大多数东西工作,但“名字”“名字”等显示为“未定义”,或者(正如你可以看到的,我在这种情况下只用名字尝试的事情)显示为“空”。 希望有

  • 问题内容: 我想从客户端上的JavaScript向我的Web应用程序(ASP.NET,IIS 7)发出定期的后台请求,但我不希望该请求影响ASP.NET会话超时。 有没有办法做到这一点? 问题答案: 您必须避免随请求一起发送cookie,因为这是会话ID的传输方式。 如果您有xmlHTTPRequest对象,则可以通过调用删除Cookie标头

  • 我有一个在AWS BeanStalk中运行的应用程序(Tomcat8+SpringMVC+PostgreSQL+EclipseLink)。 我正在使用: eclipselink-org.eclipse.persistence.jpa-2.5.2 Spring MVC-许多特性-4.1.4.发布 postgreSQL-org.postgreSQL-9.3-1100-jdbc41 并将扩展的JpaTr

  • 有没有办法在Spring MVC中获取当前会话,但不是通过请求。通常,我们所做的是在操作/控制器类方法中获取请求。从这个请求中,我们逐个请求获得会话。getSession()。但是,有没有办法在没有此请求对象的情况下获取此会话? 我的动机是,在一个实用程序类中,我需要访问会话中设置的值,而这个实用程序类方法是从控制器类的50多个方法中访问的。如果我必须从请求中获得会话,那么我需要更改所有这50个位

  • 问题内容: 我正在使用Angular框架编写单页应用程序。我是新来的。我已经阅读了本指南,以帮助我了解jQuery和Angular之间的根本区别,并且我想尽可能地遵循本指南,而不使用jQuery。 除了jQuery可以解决一些浏览器不兼容问题之外,并提供有用的函数库,例如能够从窗口顶部知道元素的顶部位置,如。没有普通的JavaScript似乎能够接近而不需要重写这个功能,在这一点岂不_是_ 一个更