我正在尝试使用Microsoft Graph删除附件。我具有以下功能:
getAccessToken(function(accessToken) {
if (accessToken) {
// Create a Graph client
var client = MicrosoftGraph.Client.init({
authProvider: done => {
// Just return the token
done(null, accessToken);
}
});
console.log(files);
files.forEach(function(file) {
client
.api(
"/me/messages/" +
file.msg +
"/attachments/" +
file.attachment
)
.delete((err, res) => {
if (err) {
console.log(err);
return;
} else {
console.log(res);
$("#attachment_" + file.list).remove();
}
});
});
} else {
var error = {
responseText: "Could not retrieve access token"
};
}
});
// OAUTH FUNCTIONS =============================
function buildAuthUrl() {
// Generate random values for state and nonce
sessionStorage.authState = guid();
sessionStorage.authNonce = guid();
var authParams = {
response_type: "id_token token",
client_id: appId,
redirect_uri: redirectUri,
scope: scopes,
state: sessionStorage.authState,
nonce: sessionStorage.authNonce,
response_mode: "fragment"
};
return authEndpoint + $.param(authParams);
}
function handleTokenResponse(hash) {
// If this was a silent request remove the iframe
$("#auth-iframe").remove();
// clear tokens
sessionStorage.removeItem("accessToken");
sessionStorage.removeItem("idToken");
var tokenresponse = parseHashParams(hash);
// Check that state is what we sent in sign in request
if (tokenresponse.state != sessionStorage.authState) {
sessionStorage.removeItem("authState");
sessionStorage.removeItem("authNonce");
// Report error
window.location.hash =
"#error=Invalid+state&error_description=The+state+in+the+authorization+response+did+not+match+the+expected+value.+Please+try+signing+in+again.";
return;
}
sessionStorage.authState = "";
sessionStorage.accessToken = tokenresponse.access_token;
// Get the number of seconds the token is valid for,
// Subract 5 minutes (300 sec) to account for differences in clock settings
// Convert to milliseconds
var expiresin =
(parseInt(tokenresponse.expires_in) - 300) * 1000;
var now = new Date();
var expireDate = new Date(now.getTime() + expiresin);
sessionStorage.tokenExpires = expireDate.getTime();
sessionStorage.idToken = tokenresponse.id_token;
validateIdToken(function(isValid) {
if (isValid) {
// Re-render token to handle refresh
renderTokens();
// Redirect to home page
window.location.hash = "#";
} else {
clearUserState();
// Report error
window.location.hash =
"#error=Invalid+ID+token&error_description=ID+token+failed+validation,+please+try+signing+in+again.";
}
});
}
function validateIdToken(callback) {
// Per Azure docs (and OpenID spec), we MUST validate
// the ID token before using it. However, full validation
// of the signature currently requires a server-side component
// to fetch the public signing keys from Azure. This sample will
// skip that part (technically violating the OpenID spec) and do
// minimal validation
if (
null == sessionStorage.idToken ||
sessionStorage.idToken.length <= 0
) {
callback(false);
}
// JWT is in three parts seperated by '.'
var tokenParts = sessionStorage.idToken.split(".");
if (tokenParts.length != 3) {
callback(false);
}
// Parse the token parts
var header = KJUR.jws.JWS.readSafeJSONString(
b64utoutf8(tokenParts[0])
);
var payload = KJUR.jws.JWS.readSafeJSONString(
b64utoutf8(tokenParts[1])
);
// Check the nonce
if (payload.nonce != sessionStorage.authNonce) {
sessionStorage.authNonce = "";
callback(false);
}
sessionStorage.authNonce = "";
// Check the audience
if (payload.aud != appId) {
callback(false);
}
// Check the issuer
// Should be https://login.microsoftonline.com/{tenantid}/v2.0
if (
payload.iss !==
"https://login.microsoftonline.com/" +
payload.tid +
"/v2.0"
) {
callback(false);
}
// Check the valid dates
var now = new Date();
// To allow for slight inconsistencies in system clocks, adjust by 5 minutes
var notBefore = new Date((payload.nbf - 300) * 1000);
var expires = new Date((payload.exp + 300) * 1000);
if (now < notBefore || now > expires) {
callback(false);
}
// Now that we've passed our checks, save the bits of data
// we need from the token.
sessionStorage.userDisplayName = payload.name;
sessionStorage.userSigninName =
payload.preferred_username;
// Per the docs at:
// https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-protocols-implicit/#send-the-sign-in-request
// Check if this is a consumer account so we can set domain_hint properly
sessionStorage.userDomainType =
payload.tid === "9188040d-6c67-4c5b-b112-36a304b66dad"
? "consumers"
: "organizations";
callback(true);
}
function makeSilentTokenRequest(callback) {
// Build up a hidden iframe
var iframe = $("<iframe/>");
iframe.attr("id", "auth-iframe");
iframe.attr("name", "auth-iframe");
iframe.appendTo("body");
iframe.hide();
iframe.load(function() {
callback(sessionStorage.accessToken);
});
iframe.attr(
"src",
buildAuthUrl() +
"&prompt=none&domain_hint=" +
sessionStorage.userDomainType +
"&login_hint=" +
sessionStorage.userSigninName
);
}
// Helper method to validate token and refresh
// if needed
function getAccessToken(callback) {
var now = new Date().getTime();
var isExpired =
now > parseInt(sessionStorage.tokenExpires);
// Do we have a token already?
if (sessionStorage.accessToken && !isExpired) {
// Just return what we have
if (callback) {
callback(sessionStorage.accessToken);
}
} else {
// Attempt to do a hidden iframe request
makeSilentTokenRequest(callback);
}
}
访问令牌
eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDNXVuYTBFVUZnVElGOEVsYXh0V2pUUEF3aGltT2hjOXAxUkdiSnVjTDcyd0pjSFdTd1lpUXNFdDdqXzgxRVd6UXhvaWRaWnVXU2d5VS1HWXRqNFFNa3JjMUNpeFFTWElNRVpYQWhSUlJXZENBQSIsImFsZyI6IlJTMjU2IiwieDV0Ijoid1VMbVlmc3FkUXVXdFZfLWh4VnRESkpaTTRRIiwia2lkIjoid1VMbVlmc3FkUXVXdFZfLWh4VnRESkpaTTRRIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9iNmFjNDlmNy1iMTNlLTQyOWMtYmI4NS0wODQ4OTY5NTA2OTkvIiwiaWF0IjoxNTQ0MTkyODUxLCJuYmYiOjE1NDQxOTI4NTEsImV4cCI6MTU0NDE5Njc1MSwiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IjQyUmdZT0JiMFhGQjBNSHFySW5FbVU5aEc4T1p6MTllOHpIRld1S0sxbldqQzVrOFAvd0IiLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6IkZvcm1wcmVzcyBjbGVhciBhdHRhY2htZW50cyIsImFwcGlkIjoiNTY0NzBlMjctZTAxNC00Zjg4LWEzY2QtZjQxODNlZjBhMjkxIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiJLYXJsc3NvbiIsImdpdmVuX25hbWUiOiJDaHJpc3RvcGhlciIsImlwYWRkciI6IjE1NS40LjE5NC4xMzQiLCJuYW1lIjoiQ2hyaXN0b3BoZXIgS2FybHNzb24iLCJvaWQiOiI5Y2JlMjBlYy1iMTk0LTRjZTYtOTU0Zi1hMTgzNTlmNGYzYTAiLCJwbGF0ZiI6IjMiLCJwdWlkIjoiMTAwMzAwMDA5QzI0MTI0NyIsInNjcCI6Ik1haWwuUmVhZCBvcGVuaWQgcHJvZmlsZSBVc2VyLlJlYWQgZW1haWwiLCJzaWduaW5fc3RhdGUiOlsia21zaSJdLCJzdWIiOiI5NVhONDhua08zbDJIeGYyTmdVTFo2YjA3WWpVV0lHOTRUQjA2bVNRUk9vIiwidGlkIjoiYjZhYzQ5ZjctYjEzZS00MjljLWJiODUtMDg0ODk2OTUwNjk5IiwidW5pcXVlX25hbWUiOiJjaHJpc3RvcGhlckBpdHBhcnRuZXJhYi5zZSIsInVwbiI6ImNocmlzdG9waGVyQGl0cGFydG5lcmFiLnNlIiwidXRpIjoiVmJGRW9EQ0RqMEMxVkFfSTNITWRBQSIsInZlciI6IjEuMCIsInhtc19zdCI6eyJzdWIiOiJka1FicDc3c2Y5ZmJlSnVYM1NqUml3aVhPa1FYOV9MZTF6MHp4X3Q4SU5BIn0sInhtc190Y2R0IjoxNDc4ODg0NzA1fQ.YQlKVdhXQcVwkcmbpY9Wx6ENro2DL7yH1rWwwkDZLD1inUrfbLRVb67lWKzgK9GnYP81d58Fp_2CZBw8C2E4X1eo02vog6_Qga9kVb8GF2-Ue0VP0KUv8EtRpEty_DBK7Re3iOkJR9yFSPQgf11Gf15l5O2mcEifrwny5nkRvab4_ssRt6hNf53V99uTFJ3_yKycGHPTobVbyQT5ZyDKxXRwoZVprFU70qrHGcBgo5emO8HbziYCUiQ9vGMpmtz61tE0U-c0E20FPC82i3zgLfMgmhNqmljZOpkOe85PFrxoep7fYkpZpWowCozugDW0E2A3SxBLZ_JHpci2R4irxg
files
是一个包含对象数组的全局变量,数据似乎是正确的。
这是我在运行代码时得到的示例响应:
{
statusCode: 403,
code: "ErrorAccessDenied",
message: "Access is denied. Check credentials and try again.",
requestId: "0739c0d9-38f2-45f7-a57d-c25dfbf92f75",
date: Fri Dec 07 2018 14:54:32 GMT+0100 (centraleuropeisk normaltid), …
}
API URL
me/messages/{id}/attachments/{id}
在https://apps.dev.microsoft.com/#/application/,我为应用程序Mail.ReadWrite
和Mail.ReadWrite.Shared
授予了访问权限,尽管它仅在注册我认为很奇怪的应用程序时提及读取。
我的应用似乎没有正确的访问权限。还有其他我想念的事情吗?我的客户查询不正确吗?
答案 0 :(得分:1)
您需要再次检查示波器。您提供的访问令牌仅包括以下范围:Mail.Read openid profile User.Read email
。
您提供的代码示例引用了一个scopes
变量,但不清楚您将其设置为什么:
var authParams = {
response_type: "id_token token",
client_id: appId,
redirect_uri: redirectUri,
scope: scopes,
state: sessionStorage.authState,
nonce: sessionStorage.authNonce,
response_mode: "fragment"
};
此属性的值应该与openid profile email Mail.ReadWrite Mail.ReadWrite.Shared
相似。