本教程是一系列教程的最后一部分,演示如何生成 React 单页应用程序(SPA),并准备使用Microsoft标识平台进行身份验证。 在本系列的第 2 部分中,你向 React SPA 添加了功能组件并生成了响应式 UI。 最后一步介绍如何在应用中测试登录和注销功能。
在本教程中,你将:
- 将代码添加到 claimUtils.js 文件以创建声明表
- 登录和退出登录应用程序
- 查看从 ID 令牌返回的声明
- 完成教程:创建用于在 React 单页应用中登录和注销的组件中的先决条件和步骤。
若要添加可显示从 ID 令牌返回的声明的表的功能,可以向 claimUtils.js 文件添加代码。 此代码片段将使用相应的说明和相应的值填充声明表。
- 打开 utils/claimUtils.js 并添加以下代码片段:
export const createClaimsTable = (claims) => {
let claimsObj = {};
let index = 0;
Object.keys(claims).forEach((key) => {
if (typeof claims[key] !== 'string' && typeof claims[key] !== 'number') return;
switch (key) {
case 'aud':
populateClaim(
key,
claims[key],
"Identifies the intended recipient of the token. In ID tokens, the audience is your app's Application ID, assigned to your app in the Microsoft Entra admin center.",
index,
claimsObj
);
index++;
break;
case 'iss':
populateClaim(
key,
claims[key],
'Identifies the issuer, or authorization server that constructs and returns the token. If the token was issued by the v2.0 endpoint, the URI will end in /v2.0.',
index,
claimsObj
);
index++;
break;
case 'iat':
populateClaim(
key,
changeDateFormat(claims[key]),
'Issued At indicates when the authentication for this token occurred.',
index,
claimsObj
);
index++;
break;
case 'nbf':
populateClaim(
key,
changeDateFormat(claims[key]),
'The nbf (not before) claim identifies the time (as UNIX timestamp) before which the JWT must not be accepted for processing.',
index,
claimsObj
);
index++;
break;
case 'exp':
populateClaim(
key,
changeDateFormat(claims[key]),
"The exp (expiration time) claim identifies the expiration time (as UNIX timestamp) on or after which the JWT must not be accepted for processing. It's important to note that in certain circumstances, a resource may reject the token before this time. For example, if a change in authentication is required or a token revocation has been detected.",
index,
claimsObj
);
index++;
break;
case 'name':
populateClaim(
key,
claims[key],
"The name claim provides a human-readable value that identifies the subject of the token. The value isn't guaranteed to be unique, it can be changed, and it's designed to be used only for display purposes. The profile scope is required to receive this claim.",
index,
claimsObj
);
index++;
break;
case 'preferred_username':
populateClaim(
key,
claims[key],
'The primary username that represents the user. It could be an email address, phone number, or a generic username without a specified format. Its value is mutable and might change over time. Since it is mutable, this value must not be used to make authorization decisions. It can be used for username hints, however, and in human-readable UI as a username. The profile scope is required in order to receive this claim.',
index,
claimsObj
);
index++;
break;
case 'nonce':
populateClaim(
key,
claims[key],
'The nonce matches the parameter included in the original /authorize request to the IDP. If it does not match, your application should reject the token.',
index,
claimsObj
);
index++;
break;
case 'oid':
populateClaim(
key,
claims[key],
'The oid (user’s object id) is the only claim that should be used to uniquely identify a user in an external tenant. The token might have one or more of the following claim, that might seem like a unique identifier, but is not and should not be used as such.',
index,
claimsObj
);
index++;
break;
case 'tid':
populateClaim(
key,
claims[key],
'The tenant ID. You will use this claim to ensure that only users from the current external tenant can access this app.',
index,
claimsObj
);
index++;
break;
case 'upn':
populateClaim(
key,
claims[key],
'(user principal name) - might be unique amongst the active set of users in a tenant but tend to get reassigned to new employees as employees leave the organization and others take their place or might change to reflect a personal change like marriage.',
index,
claimsObj
);
index++;
break;
case 'email':
populateClaim(
key,
claims[key],
'Email might be unique amongst the active set of users in a tenant but tend to get reassigned to new employees as employees leave the organization and others take their place.',
index,
claimsObj
);
index++;
break;
case 'acct':
populateClaim(
key,
claims[key],
'Available as an optional claim, it lets you know what the type of user (homed, guest) is. For example, for an individual’s access to their data you might not care for this claim, but you would use this along with tenant id (tid) to control access to say a company-wide dashboard to just employees (homed users) and not contractors (guest users).',
index,
claimsObj
);
index++;
break;
case 'sid':
populateClaim(key, claims[key], 'Session ID, used for per-session user sign-out.', index, claimsObj);
index++;
break;
case 'sub':
populateClaim(
key,
claims[key],
'The sub claim is a pairwise identifier - it is unique to a particular application ID. If a single user signs into two different apps using two different client IDs, those apps will receive two different values for the subject claim.',
index,
claimsObj
);
index++;
break;
case 'ver':
populateClaim(
key,
claims[key],
'Version of the token issued by the Microsoft identity platform',
index,
claimsObj
);
index++;
break;
case 'uti':
case 'rh':
index++;
break;
case '_claim_names':
case '_claim_sources':
default:
populateClaim(key, claims[key], '', index, claimsObj);
index++;
}
});
return claimsObj;
};
/**
* Populates claim, description, and value into an claimsObject
* @param {String} claim
* @param {String} value
* @param {String} description
* @param {Number} index
* @param {Object} claimsObject
*/
const populateClaim = (claim, value, description, index, claimsObject) => {
let claimsArray = [];
claimsArray[0] = claim;
claimsArray[1] = value;
claimsArray[2] = description;
claimsObject[index] = claimsArray;
};
/**
* Transforms Unix timestamp to date and returns a string value of that date
* @param {String} date Unix timestamp
* @returns
*/
const changeDateFormat = (date) => {
let dateObj = new Date(date * 1000);
return `${date} - [${dateObj.toString()}]`;
};
所有需要的代码片段均已添加后,现在可以在 Web 浏览器中调用和测试应用程序。
打开新终端并运行以下命令以启动 Express Web 服务器。
npm start
复制终端中显示的
http
URL,例如http://localhost:3000
,并将其粘贴到浏览器中。 建议使用专用或隐身浏览器会话。使用注册到租户的帐户登录。
将显示类似于以下屏幕截图的界面,指示你已登录到应用程序。 如果已添加声明表,可以查看从 ID 令牌返回的声明。
- 在页面上找到 “注销 ”按钮,然后选择它。
- 系统将提示你选择要退出登录的帐户。 选择用于登录的帐户。
此时会显示一条消息,指示你已注销。现在可以关闭浏览器窗口。
- 快速入门:使用Microsoft标识平台保护 ASP.NET 核心 Web API。
- 在以下多部分系列教程中,详细了解如何构建一个让用户登录的 React SPA。