由于 MSAL Node 支持各种授权代码授予,因此支持每个授予的不同公共 API 和相应的请求。 本文将带你了解每种流程可用的不同公共 API 及其对应的请求类型。 强烈建议为应用程序实现授权代码流。
授权代码流程
公共 API
getAuthCodeUrl():该 API 是 MSAL Node 的
authorization code grant的第一步。 请求的类型为 AuthorizationUrlRequest。 应用程序发送的 URL 可用于生成authorization code。 此 URL 可在所选的浏览器中打开,用户可以在其中输入凭据,并使用authorization code将其重定向回redirectUri(在应用注册期间注册)。authorization code现在可以通过以下步骤兑换为token。 请注意,如果正在为公共客户端应用程序执行授权代码流,建议 使用 PKCE 。acquireTokenByCode():此 API 是 MSAL Node 的
authorization code grant的第二部分。 此处构造的请求应为 AuthorizationCodeRequest 类型。 应用程序传递了在上一步骤中接收的authorization code,并将其替换为token。 请注意,如果为公共客户端应用程序执行授权代码流程,建议使用 PKCE。
const authCodeUrlParameters = {
scopes: ["sample_scope"],
redirectUri: "your_redirect_uri",
};
// get url to sign user in and consent to scopes needed for application
cca.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
console.log(response);
}).catch((error) => console.log(JSON.stringify(error)));
const tokenRequest = {
code: "authorization_code",
redirectUri: "your_redirect_uri",
scopes: ["sample_scope"],
};
// acquire a token by exchanging the code
cca.acquireTokenByCode(tokenRequest).then((response) => {
console.log("\nResponse: \n:", response);
}).catch((error) => {
console.log(error);
});
设备代码流
公共 API
-
acquireTokenByDeviceCode():此 API 允许应用程序使用设备代码授予获取令牌。 请求的类型为 DeviceCodeRequest。 此 API 通过 OAuth2.0 设备代码流从授权机构获取
token。 此流专为无权访问浏览器或具有输入约束的设备而设计。 授权服务器颁发一个 DeviceCode 对象,其中包含验证代码、最终用户代码以及最终用户验证 URI。 DeviceCode 对象通过回调提供,应指示最终用户使用其他设备导航到验证 URI 以输入凭据。 由于客户端无法接收传入请求,因此它会重复轮询授权服务器,直到最终用户完成凭据输入。
const msalConfig = {
auth: {
clientId: "your_client_id_here",
authority: "your_authority_here",
}
};
const pca = new msal.PublicClientApplication(msalConfig);
const deviceCodeRequest = {
deviceCodeCallback: (response) => (console.log(response.message)),
scopes: ["user.read"],
};
pca.acquireTokenByDeviceCode(deviceCodeRequest).then((response) => {
console.log(JSON.stringify(response));
}).catch((error) => {
console.log(JSON.stringify(error));
});
刷新令牌流
公共 API
-
acquireTokenByRefreshToken:此 API 通过交换为新令牌集提供的刷新令牌来获取令牌。 请求的类型为 RefreshTokenRequest。
refresh token永远不会在响应中返回给用户,但可以从用户缓存中访问。 建议您在非交互式场景中使用acquireTokenSilent()。 使用 acquireTokenSilent()时,MSAL 将自动处理令牌的缓存和刷新。
const config = {
auth: {
clientId: "your_client_id_here",
authority: "your_authority_here",
}
};
const pca = new msal.PublicClientApplication(config);
const refreshTokenRequest = {
refreshToken: "",
scopes: ["user.read"],
};
pca.acquireTokenByRefreshToken(refreshTokenRequest).then((response) => {
console.log(JSON.stringify(response));
}).catch((error) => {
console.log(JSON.stringify(error));
});
静默流
公共 API
-
acquireTokenSilent:此 API 以静默方式获取令牌,适用于用户提供了缓存的情况,或者在此次调用之前先执行了任何其他交互式流程(例如:授权码流)并已创建缓存的情况。 请求的类型为 SilentFlowRequest。 当用户指定请求令牌所对应的帐户时,系统会自动获取
token。
/**
* Cache Plugin configuration
*/
const cachePath = "path_to_your_cache_file/msal_cache.json"; // Replace this string with the path to your valid cache file.
const readFromStorage = () => {
return fs.readFile(cachePath, "utf-8");
};
const writeToStorage = (getMergedState) => {
return readFromStorage().then(oldFile =>{
const mergedState = getMergedState(oldFile);
return fs.writeFile(cachePath, mergedState);
})
};
const cachePlugin = {
readFromStorage,
writeToStorage
};
/**
* Public Client Application Configuration
*/
const publicClientConfig = {
auth: {
clientId: "your_client_id_here",
authority: "your_authority_here",
redirectUri: "your_redirectUri_here",
},
cache: {
cachePlugin
},
};
/** Request Configuration */
const scopes = ["your_scopes"];
const authCodeUrlParameters = {
scopes: scopes,
redirectUri: "your_redirectUri_here",
};
const pca = new msal.PublicClientApplication(publicClientConfig);
const msalCacheManager = pca.getCacheManager();
let accounts;
pca.getAuthCodeUrl(authCodeUrlParameters)
.then((response) => {
console.log(response);
}).catch((error) => console.log(JSON.stringify(error)));
const tokenRequest = {
code: req.query.code,
redirectUri: "http://localhost:3000/redirect",
scopes: scopes,
};
pca.acquireTokenByCode(tokenRequest).then((response) => {
console.log("\nResponse: \n:", response);
return msalCacheManager.writeToPersistence();
}).catch((error) => {
console.log(error);
});
// get Accounts
accounts = msalCacheManager.getAllAccounts();
// Build silent request
const silentRequest = {
account: accounts[0], // You would filter accounts to get the account you want to get tokens for
scopes: scopes,
};
// Acquire Token Silently to be used in MS Graph call
pca.acquireTokenSilent(silentRequest).then((response) => {
console.log("\nSuccessful silent token acquisition:\nResponse: \n:", response);
return msalCacheManager.writeToPersistence();
}).catch((error) => {
console.log(error);
});
客户端凭据流程
公共 API
- acquireTokenByClientCredential:此 API 使用机密客户端应用程序的凭据获取令牌,以便在调用另一个 Web 服务时进行身份验证(而不是模拟用户)。 在此方案中,客户端通常是中间层 Web 服务、守护程序服务或后端 Web 应用程序。 为了进行更高级别的保证,Microsoft 标识平台还允许调用服务将证书(而不是共享机密)用作凭据。 请求的类型为 ClientCredentialRequest。
安全地使用机密
不应对机密进行硬编码。 dotenv npm 包可用于将机密存储在 .env 文件(位于项目的根目录中)中,该文件应包含在 .gitignore 中,以防止意外上传机密。
import "dotenv/config"; // process.env now has the values defined in a .env file
const config = {
auth: {
clientId: "your_client_id_here",
authority: "your_authority_here",
clientSecret: process.env.clientSecret
}
};
// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);
// With client credentials flows permissions need to be granted in the portal by a tenant administrator.
// The scope is always in the format "<resource>/.default"
const clientCredentialRequest = {
scopes: ["https://graph.microsoft.com/.default"], // replace with your resource
};
cca.acquireTokenByClientCredential(clientCredentialRequest).then((response) => {
console.log("Response: ", response);
}).catch((error) => {
console.log(JSON.stringify(error));
});
代理流
- acquireTokenOnBehalfOf:此 API 实现 On-Behalf-Of 流程,当应用程序调用某个服务/Web API,而该服务/Web API 又需要调用另一个采用其他身份验证流(设备代码、用户名/密码等)的服务/Web API 时,会使用此流程。 访问令牌最初由 Web API 通过任一 Web API 流程获取,随后 Web API 可以通过 OBO 将此令牌交换为另一个令牌。 请求的类型为 OnBehalfOfRequest
有关使用说明,请查看代理流示例: