客户端密码或客户端证书
鉴于 Web 应用现在调用下游的 Web API,请提供 appsettings.json 文件中客户端密码或客户端证书。 你还可以添加一个节来指定:
- 下游 Web API 的 URL
- 调用 API 所需的范围
在下面的示例中,GraphBeta
节指定了这些设置。
{
"AzureAd": {
"Instance": "https://login.partner.microsoftonline.cn/",
"ClientId": "[Enter_the_Application_Id_Here]",
"TenantId": "common",
// To call an API
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret":"[Enter_the_Client_Secret_Here]"
}
]
},
"GraphBeta": {
"BaseUrl": "https://microsoftgraph.chinacloudapi.cn/beta",
"Scopes": ["https://microsoftgraph.chinacloudapi.cn/user.read"]
}
}
注意
你可建议一组客户端凭据,其中包括无凭据解决方案,例如 Azure Kubernetes 的工作负载联合身份验证。
先前版本的 Microsoft.Identity.Web 在单个属性“ClientSecret”中(而非“ClientCredentials”中)表示客户端密码。 这仍然支持向后兼容,但你不能同时使用“ClientSecret”属性和“ClientCredentials”集合。
你可以提供客户端证书,而不是客户端密码。 以下代码片段演示如何使用存储在 Azure Key Vault 中的证书。
{
"AzureAd": {
"Instance": "https://login.partner.microsoftonline.cn/",
"ClientId": "[Enter_the_Application_Id_Here]",
"TenantId": "common",
// To call an API
"ClientCredentials": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://msidentitywebsamples.vault.azure.cn",
"KeyVaultCertificateName": "MicrosoftIdentitySamplesCert"
}
]
},
"GraphBeta": {
"BaseUrl": "https://microsoftgraph.chinacloudapi.cn/beta",
"Scopes": ["https://microsoftgraph.chinacloudapi.cn/user.read"]
}
}
警告
如果忘记将 Scopes
更改为数组,则当尝试使用 IDownstreamApi
时,范围会显示为 null,并且 IDownstreamApi
会尝试匿名(未经身份验证)调用下游 API,这会导致 401/unauthenticated
。
Microsoft.Identity.Web 提供了多种通过配置或代码描述证书的方法。 有关详细信息,请参阅 GitHub 上的 Microsoft.Identity.Web - 使用证书。
修改 Startup.cs 文件
Web 应用需要获取下游 API 的令牌。 可通过在 .AddMicrosoftIdentityWebApp(Configuration)
后面添加 .EnableTokenAcquisitionToCallDownstreamApi()
行来指定它。 此行公开 IAuthorizationHeaderProvider
服务,可在控制器和页面操作中使用该服务。 不过,正如你将在以下两个选项中看到的那样,该操作可以更简单地完成。 还需要在 Startup.cs 中选择令牌缓存实现(例如 .AddInMemoryTokenCaches()
):
using Microsoft.Identity.Web;
public class Startup
{
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(new string[]{"https://microsoftgraph.chinacloudapi.cn/user.read" })
.AddInMemoryTokenCaches();
// ...
}
// ...
}
传递给 EnableTokenAcquisitionToCallDownstreamApi
的范围是可选项,使 Web 应用能够请求范围并在用户登录时向用户征求对这些范围的许可。 如果未指定范围,Microsoft.Identity.Web 会启用增量许可体验。
Microsoft.Identity.Web 提供了两种从 Web 应用调用 Web API 的机制,而不要求你获取令牌。 选择哪种方式取决于你是要调用 Microsoft Graph 还是调用另一个 API。
选项 1:调用 Microsoft Graph
如果要调用 Microsoft Graph,则可通过 Microsoft.Identity.Web 在 API 操作中直接使用 GraphServiceClient
(由 Microsoft Graph SDK 公开)。 若要公开 Microsoft Graph,请执行以下操作:
将 Microsoft.Identity.Web.GraphServiceClient NuGet 包添加到项目。
在 Startup.cs 文件的 .EnableTokenAcquisitionToCallDownstreamApi()
后面添加 .AddMicrosoftGraph()
。 .AddMicrosoftGraph()
具有多个重写。 使用将配置部分作为参数的重写,代码变为:
using Microsoft.Identity.Web;
public class Startup
{
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(new string[]{"https://microsoftgraph.chinacloudapi.cn/user.read" })
.AddMicrosoftGraph(Configuration.GetSection("GraphBeta"))
.AddInMemoryTokenCaches();
// ...
}
// ...
}
选项 2:调用下游 Web API,而不是 Microsoft Graph
如果要调用 API 而不是 Microsoft Graph,可通过 Microsoft.Identity.Web 在 API 操作中使用 IDownstreamApi
接口。 若要使用此接口,请执行以下操作:
将 Microsoft.Identity.Web.DownstreamApi NuGet 包添加到项目中。
在 Startup.cs 文件的 .EnableTokenAcquisitionToCallDownstreamApi()
后面添加 .AddDownstreamApi()
。 .AddDownstreamApi()
具有两个参数,如以下代码片段所示:
- 服务 (API) 的名称,用于在控制器操作中引用相应的配置
- 表示用于调用下游 Web API 的参数的配置部分。
using Microsoft.Identity.Web;
public class Startup
{
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(new string[]{"https://microsoftgraph.chinacloudapi.cn/user.read" })
.AddDownstreamApi("MyApi", Configuration.GetSection("GraphBeta"))
.AddInMemoryTokenCaches();
// ...
}
// ...
}
总结
与 Web API 一样,你可以选择各种令牌缓存实现。 有关详细信息,请参阅 GitHub 上的 Microsoft.Identity.Web - 令牌缓存序列化。
下图显示 Microsoft.Identity.Web 的各种可能性及其对 Startup.cs 文件的影响:
客户端密码或客户端证书
鉴于 Web 应用现在调用下游的 Web API,请提供 appsettings.json 文件中客户端密码或客户端证书。 你还可以添加一个节来指定:
- 下游 Web API 的 URL
- 调用 API 所需的范围
在下面的示例中,GraphBeta
节指定了这些设置。
{
"AzureAd": {
"Instance": "https://login.partner.microsoftonline.cn/",
"ClientId": "[Enter_the_Application_Id_Here]",
"TenantId": "common",
// To call an API
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret":"[Enter_the_Client_Secret_Here]"
}
]
},
"GraphBeta": {
"BaseUrl": "https://microsoftgraph.chinacloudapi.cn/beta",
"Scopes": ["https://microsoftgraph.chinacloudapi.cn/user.read"]
}
}
注意
你可建议一组客户端凭据,其中包括无凭据解决方案,例如 Azure Kubernetes 的工作负载联合身份验证。
先前版本的 Microsoft.Identity.Web 在单个属性“ClientSecret”中(而非“ClientCredentials”中)表示客户端密码。 这仍然支持向后兼容,但你不能同时使用“ClientSecret”属性和“ClientCredentials”集合。
你可以提供客户端证书,而不是客户端密码。 以下代码片段演示如何使用存储在 Azure Key Vault 中的证书。
{
"AzureAd": {
"Instance": "https://login.partner.microsoftonline.cn/",
"ClientId": "[Enter_the_Application_Id_Here]",
"TenantId": "common",
// To call an API
"ClientCredentials": [
{
"SourceType": "KeyVault",
"KeyVaultUrl": "https://msidentitywebsamples.vault.azure.cn",
"KeyVaultCertificateName": "MicrosoftIdentitySamplesCert"
}
]
},
"GraphBeta": {
"BaseUrl": "https://microsoftgraph.chinacloudapi.cn/beta",
"Scopes": ["https://microsoftgraph.chinacloudapi.cn/user.read"]
}
}
警告
如果忘记将 Scopes
更改为数组,则当尝试使用 IDownstreamApi
时,范围会显示为 null,并且 IDownstreamApi
会尝试匿名(未经身份验证)调用下游 API,这会导致 401/unauthenticated
。
Microsoft.Identity.Web 提供了多种通过配置或代码描述证书的方法。 有关详细信息,请参阅 GitHub 上的 Microsoft.Identity.Web - 使用证书。
Startup.Auth.cs
Web 应用需要获取下游 API 的令牌,Microsoft.Identity.Web 提供了两种用来从 Web 应用调用 Web API 的机制。 选择哪种方式取决于你是要调用 Microsoft Graph 还是调用另一个 API。
选项 1:调用 Microsoft Graph
如果要调用 Microsoft Graph,则可通过 Microsoft.Identity.Web 在 API 操作中直接使用 GraphServiceClient
(由 Microsoft Graph SDK 公开)。 若要公开 Microsoft Graph,请执行以下操作:
- 将 Microsoft.Identity.Web.GraphServiceClient NuGet 包添加到项目。
- 将
.AddMicrosoftGraph()
添加到 Startup.Auth.cs 文件中的服务集合。 .AddMicrosoftGraph()
具有多个重写。 使用将配置部分作为参数的重写,代码变为:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.IdentityModel.Validators;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Owin;
namespace WebApp
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
// Get an TokenAcquirerFactory specialized for OWIN
OwinTokenAcquirerFactory owinTokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
// Configure the web app.
app.AddMicrosoftIdentityWebApp(owinTokenAcquirerFactory,
updateOptions: options => {});
// Add the services you need.
owinTokenAcquirerFactory.Services
.Configure<ConfidentialClientApplicationOptions>(options =>
{ options.RedirectUri = "https://localhost:44326/"; })
.AddMicrosoftGraph()
.AddInMemoryTokenCaches();
owinTokenAcquirerFactory.Build();
}
}
}
选项 2:调用下游 Web API,而不是 Microsoft Graph
如果要调用 API 而不是 Microsoft Graph,可通过 Microsoft.Identity.Web 在 API 操作中使用 IDownstreamApi
接口。 若要使用此接口,请执行以下操作:
- 将 Microsoft.Identity.Web.DownstreamApi NuGet 包添加到项目中。
- 在 Startup.cs 文件的
.EnableTokenAcquisitionToCallDownstreamApi()
后面添加 .AddDownstreamApi()
。 .AddDownstreamApi()
有两个参数:
- 服务 (API) 的名称:你可以在控制器操作中使用此名称来引用相应的配置
- 表示用于调用下游 Web API 的参数的配置部分。
代码如下:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.IdentityModel.Validators;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Owin;
namespace WebApp
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
// Get a TokenAcquirerFactory specialized for OWIN.
OwinTokenAcquirerFactory owinTokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
// Configure the web app.
app.AddMicrosoftIdentityWebApp(owinTokenAcquirerFactory,
updateOptions: options => {});
// Add the services you need.
owinTokenAcquirerFactory.Services
.Configure<ConfidentialClientApplicationOptions>(options =>
{ options.RedirectUri = "https://localhost:44326/"; })
.AddDownstreamApi("Graph", owinTokenAcquirerFactory.Configuration.GetSection("GraphBeta"))
.AddInMemoryTokenCaches();
owinTokenAcquirerFactory.Build();
}
}
}
总结
你可以选择各种令牌缓存实现。 有关详细信息,请参阅 GitHub 上的 Microsoft.Identity.Web - 令牌缓存序列化。
下图显示 Microsoft.Identity.Web 的各种可能性及其对 Startup.cs 文件的影响:
本文以及下一篇文章中的代码示例都是从 ASP.NET Web 应用示例中提取的。 不妨参阅相应示例来获取完整的实现详细信息。
实现 Java 代码示例
本文以及下一篇文章中的代码示例都是从使用适用于 Java 的 MSAL 的 Web 应用示例调用 Microsoft Graph 的 Java Web 应用中提取的。
此示例当前让适用于 Java 的 MSAL 生成授权代码 URL,并处理导航到 Microsoft 标识平台的授权终结点。 也可以使用冲刺 (sprint) 安全机制来登录用户。 不妨参阅相应示例来获取完整的实现详细信息。
实现 Node.js 代码示例
本文中的代码示例及以下内容摘自调用 Microsoft Graph 的 Node.js 和 Express.js Web 应用程序(使用 MSAL Node 的 Web 应用示例)。
此示例当前让 MSAL Node 生成授权代码 URL,并处理导航到 Microsoft 标识平台的授权终结点。 如下所示:
/**
* Prepares the auth code request parameters and initiates the first leg of auth code flow
* @param req: Express request object
* @param res: Express response object
* @param next: Express next function
* @param authCodeUrlRequestParams: parameters for requesting an auth code url
* @param authCodeRequestParams: parameters for requesting tokens using auth code
*/
redirectToAuthCodeUrl(authCodeUrlRequestParams, authCodeRequestParams, msalInstance) {
return async (req, res, next) => {
// Generate PKCE Codes before starting the authorization flow
const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes();
// Set generated PKCE codes and method as session vars
req.session.pkceCodes = {
challengeMethod: 'S256',
verifier: verifier,
challenge: challenge,
};
/**
* By manipulating the request objects below before each request, we can obtain
* auth artifacts with desired claims. For more information, visit:
* https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationurlrequest
* https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationcoderequest
**/
req.session.authCodeUrlRequest = {
...authCodeUrlRequestParams,
responseMode: msal.ResponseMode.FORM_POST, // recommended for confidential clients
codeChallenge: req.session.pkceCodes.challenge,
codeChallengeMethod: req.session.pkceCodes.challengeMethod,
};
req.session.authCodeRequest = {
...authCodeRequestParams,
code: '',
};
try {
const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
res.redirect(authCodeUrlResponse);
} catch (error) {
next(error);
}
};
}
Microsoft.Identity.Web.OWIN 将通过设置正确的 OpenID Connect 设置、订阅代码接收的事件和兑换代码来简化代码。 兑换授权代码不需要其他代码。 请参阅 Microsoft.Identity.Web 源代码,详细了解其原理。
AuthProvider 类中的 handleRedirect 方法处理从 Microsoft Entra ID 接收的授权代码。 如下所示:
handleRedirect(options = {}) {
return async (req, res, next) => {
if (!req.body || !req.body.state) {
return next(new Error('Error: response not found'));
}
const authCodeRequest = {
...req.session.authCodeRequest,
code: req.body.code,
codeVerifier: req.session.pkceCodes.verifier,
};
try {
const msalInstance = this.getMsalInstance(this.msalConfig);
if (req.session.tokenCache) {
msalInstance.getTokenCache().deserialize(req.session.tokenCache);
}
const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
req.session.tokenCache = msalInstance.getTokenCache().serialize();
req.session.idToken = tokenResponse.idToken;
req.session.account = tokenResponse.account;
req.session.isAuthenticated = true;
const state = JSON.parse(this.cryptoProvider.base64Decode(req.body.state));
res.redirect(state.successRedirect);
} catch (error) {
next(error);
}
}
}
若要了解 Java 示例如何获取授权代码,请参阅用于登录用户的 Web 应用:代码配置。 在应用收到授权代码后,AuthFilter.java#L51-L56:
- 将授权代码委派给 AuthHelper.java#L67-L97 中的
AuthHelper.processAuthenticationCodeRedirect
方法。
- 调用
getAuthResultByAuthCode
。
class AuthHelper {
// Code omitted
void processAuthenticationCodeRedirect(HttpServletRequest httpRequest, String currentUri, String fullUrl)
throws Throwable {
// Code omitted
AuthenticationResponse authResponse = AuthenticationResponseParser.parse(new URI(fullUrl), params);
// Code omitted
IAuthenticationResult result = getAuthResultByAuthCode(
httpRequest,
oidcResponse.getAuthorizationCode(),
currentUri);
// Code omitted
}
}
getAuthResultByAuthCode
方法是在 AuthHelper.java#L176 中定义。 它创建 MSAL ConfidentialClientApplication
,然后使用通过授权代码创建的 AuthorizationCodeParameters
来调用 acquireToken()
。
private IAuthenticationResult getAuthResultByAuthCode(
HttpServletRequest httpServletRequest,
AuthorizationCode authorizationCode,
String currentUri) throws Throwable {
IAuthenticationResult result;
ConfidentialClientApplication app;
try {
app = createClientApplication();
String authCode = authorizationCode.getValue();
AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(
authCode,
new URI(currentUri)).
build();
Future<IAuthenticationResult> future = app.acquireToken(parameters);
result = future.get();
} catch (ExecutionException e) {
throw e.getCause();
}
if (result == null) {
throw new ServiceUnavailableException("authentication result was null");
}
SessionManagementHelper.storeTokenCacheInSession(httpServletRequest, app.tokenCache().serialize());
return result;
}
private ConfidentialClientApplication createClientApplication() throws MalformedURLException {
return ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.create(clientSecret)).
authority(authority).
build();
}
若要了解 Python 示例如何获取授权代码,请参阅用于登录用户的 Web 应用:代码配置。
Microsoft 登录屏幕将授权代码发送到注册应用时指定的 /getAToken
URL。 auth_response
路由处理该 URL,调用 auth.complete_login
来处理授权代码,然后返回错误或重定向到主页。
@app.route(app_config.REDIRECT_PATH)
def auth_response():
result = auth.complete_log_in(request.args)
if "error" in result:
return render_template("auth_error.html", result=result)
return redirect(url_for("index"))
有关此代码的完整上下文,请参阅 app.py。
ASP.NET Core 教程使用依赖关系注入,让你能够在应用的 Startup.cs 文件中确定令牌缓存实现。 Microsoft.Identity.Web 随附了令牌缓存序列化中所述的预生成令牌缓存序列化程序。 一个有意思的地方是,可以选择 ASP.NET Core 分布式内存缓存:
// Use a distributed token cache by adding:
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(
initialScopes: new string[] { "https://microsoftgraph.chinacloudapi.cn/user.read" })
.AddDistributedTokenCaches();
// Then, choose your implementation.
// For instance, the distributed in-memory cache (not cleared when you stop the app):
services.AddDistributedMemoryCache();
// Or a Redis cache:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "SampleInstance";
});
// Or even a SQL Server token cache:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = _config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
有关令牌缓存提供程序的详细信息,另请参阅 Microsoft.Identity.Web 的令牌缓存序列化一文,以及 Web 应用教程的 ASP.NET Core Web 应用教程 | 令牌缓存部分。
ASP.NET 教程将使用依赖关系注入,让你能够在 Startup.Auth.cs 文件中为应用程序确定令牌缓存实现。 Microsoft.Identity.Web 随附了令牌缓存序列化中所述的预生成令牌缓存序列化程序。 一个有意思的地方是,可以选择 ASP.NET Core 分布式内存缓存:
var services = owinTokenAcquirerFactory.Services;
// Use a distributed token cache by adding:
services.AddDistributedTokenCaches();
// Then, choose your implementation.
// For instance, the distributed in-memory cache (not cleared when you stop the app):
services.AddDistributedMemoryCache();
// Or a Redis cache:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "SampleInstance";
});
// Or even a SQL Server token cache:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = _config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
有关令牌缓存提供程序的详细信息,另请参阅 Microsoft.Identity.Web 令牌缓存序列化一文,以及 Web 应用教程的 ASP.NET Core Web 应用教程 | 令牌缓存部分。
有关详细信息,请参阅 MSAL.NET 中的令牌缓存序列化。
MSAL Java 提供了用于序列化和反序列化令牌缓存的方法。 Java 示例处理来自会话的序列化,如 AuthHelper.java#L99-L122 中的 getAuthResultBySilentFlow
方法所示:
IAuthenticationResult getAuthResultBySilentFlow(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws Throwable {
IAuthenticationResult result = SessionManagementHelper.getAuthSessionObject(httpRequest);
IConfidentialClientApplication app = createClientApplication();
Object tokenCache = httpRequest.getSession().getAttribute("token_cache");
if (tokenCache != null) {
app.tokenCache().deserialize(tokenCache.toString());
}
SilentParameters parameters = SilentParameters.builder(
Collections.singleton("https://microsoftgraph.chinacloudapi.cn/User.Read"),
result.account()).build();
CompletableFuture<IAuthenticationResult> future = app.acquireTokenSilently(parameters);
IAuthenticationResult updatedResult = future.get();
// Update session with latest token cache.
SessionManagementHelper.storeTokenCacheInSession(httpRequest, app.tokenCache().serialize());
return updatedResult;
}
适用于 Java 的 MSAL 示例中提供了 SessionManagementHelper
类的详细信息。
在 Node.js 示例中,应用会话用于存储令牌缓存。 使用 MSAL Node 缓存方法,在发出令牌请求之前读取会话中的令牌缓存,然后在令牌请求成功完成后进行更新。 如下所示:
acquireToken(options = {}) {
return async (req, res, next) => {
try {
const msalInstance = this.getMsalInstance(this.msalConfig);
/**
* If a token cache exists in the session, deserialize it and set it as the
* cache for the new MSAL CCA instance. For more, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/caching.md
*/
if (req.session.tokenCache) {
msalInstance.getTokenCache().deserialize(req.session.tokenCache);
}
const tokenResponse = await msalInstance.acquireTokenSilent({
account: req.session.account,
scopes: options.scopes || [],
});
/**
* On successful token acquisition, write the updated token
* cache back to the session. For more, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/caching.md
*/
req.session.tokenCache = msalInstance.getTokenCache().serialize();
req.session.accessToken = tokenResponse.accessToken;
req.session.idToken = tokenResponse.idToken;
req.session.account = tokenResponse.account;
res.redirect(options.successRedirect);
} catch (error) {
if (error instanceof msal.InteractionRequiredAuthError) {
return this.login({
scopes: options.scopes || [],
redirectUri: options.redirectUri,
successRedirect: options.successRedirect || '/',
})(req, res, next);
}
next(error);
}
};
}
在 Python 示例中,身份包使用全局 session
对象进行存储,处理令牌缓存。
Flask 已内置支持存储在 Cookie 中的会话,但由于身份 Cookie 的长度,本示例改为使用 Flask-会话包。 一切都在 app.py 中进行初始化:
import identity
import identity.web
import requests
from flask import Flask, redirect, render_template, request, session, url_for
from flask_session import Session
import app_config
app = Flask(__name__)
app.config.from_object(app_config)
Session(app)
auth = identity.web.Auth(
session=session,
authority=app.config["AUTHORITY"],
client_id=app.config["CLIENT_ID"],
client_credential=app.config["CLIENT_SECRET"],
)
由于 app_config.py
中的 SESSION_TYPE="filesystem"
设置,Flask-会话包使用本地文件系统存储会话。
在生产环境下,应使用在多个实例依然保留且部署你应用程序的设置,例如“sqlachemy”或“redis”。