Microsoft Entra(Azure ADD) MSAL库SSO OAuth2登录详解
Author:zhoulujun Date:
《Microsoft 标识平台身份验证库 (MSAL) 使用:react+MsalProvider鉴权》 使用起来比较简单,但是交互流程是怎么样的呢?
Microsoft 标识平台支持各种新式应用体系结构的身份验证,所有这些体系结构都基于行业标准协议 OAuth 2.0 或 OpenID Connect。
这里安利下:《单点登录之身份验证与授权:CAS/OAuth/SAML/OpenID》
单页应用
单页应用 (SPA) 前端, Microsoft 标识平台支持这些应用的方式是使用 OpenID Connect 协议进行身份验证,以及使用 OAuth 2.0 定义的两种授权类型之一。
再安利下《OAuth 2.0 扩展协议之PKCE》
OAuth 2.0交互流程如下
分为三个步骤:
请求授权代码(获取code)
兑换访问令牌的代码(通过code换取accessToken)
使用访问令牌获取用户信息(校验token并获取用户信息,并获取登陆用户信息)
请求授权代码:/oauth2/v2.0/authorize
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
重定向进入登录页:重定向页面接口,跳转P10登陆窗口,并回调code给 业务
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize? client_id=00001111-aaaa-2222-bbbb-3333cccc4444 &response_type=code &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F &response_mode=query &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read &state=12345 &code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl &code_challenge_method=S256
用户经过身份验证并授予同意后,Microsoft 标识平台将使用 response_mode 参数中指定的方法,将响应返回到位于所指示的 redirect_uri 的应用。
GET http://localhost? code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCmLdgfSTLEMPGYuNHSUYBrq... &state=12345
发现已经存在登陆态,通过接口https://login.microsoftonline.com/kmsi 返回302重定向返回code
参数说明:
参数 | 选择 | 说明 |
---|---|---|
tenant | 必需 | 请求路径中的 {tenant} 值可用于控制哪些用户可以登录应用程序。 有效值为 common、organizations、consumers 和租户标识符。 对于用户从一个租户登录到另一个租户的来宾场景,必须提供租户标识符才能让其登录到资源租户。 有关详细信息,请参阅终结点。 |
client_id | 必答 | Microsoft Entra 管理中心 - 应用注册体验分配给应用的“应用程序(客户端) ID”。 |
response_type | 必答 | 必须包括授权代码流的 code 。 如果使用混合流,则还可以包括 id_token 或 token。 |
redirect_uri | 必需 | 应用的 redirect_uri,你的应用可通过该应用发送和接收身份验证响应。 其必须完全符合在 Microsoft Entra 管理中心中注册的其中一个重定向 URI,否则必须是编码的 URL。 对于本机应用和移动应用,请使用一个建议的值:https://login.microsoftonline.com/common/oauth2/nativeclient(适用于使用嵌入式浏览器的应用)或 http://localhost(适用于使用系统浏览器的应用)。 |
scope | 必需 | 希望用户同意的范围的空格分隔列表。 对于请求的 /authorize 分支,此参数可以涵盖多个资源。 此值允许应用获取你要调用的多个 Web API 的同意。 |
response_mode | 建议 | 指定标识平台应如何将请求的令牌返回到应用。 支持的值: - query:请求访问令牌时的默认值。 在重定向 URI 上提供代码作为查询字符串参数。 使用隐式流请求 ID 令牌时不支持该 query 参数。 - fragment:通过使用隐式流请求 ID 令牌时的默认值。 如果只请求一个代码,也支持。 - form_post:对重定向 URI 执行包含代码的 POST。 请求代码时支持。 |
state | 建议 | 同时随令牌响应返回的请求中所包含的值。 可以是想要的任何内容的字符串。 随机生成的唯一值通常用于 防止跨站点请求伪造攻击。 该值还可用于在身份验证请求发生前,对有关用户在应用中的状态信息进行编码。 例如,它可以对用户所在的页面或视图进行编码。 |
prompt | 可选 | 表示需要的用户交互类型。 有效值为 login、none、consent 和 select_account。 - prompt=login 强制用户在该请求上输入其凭据,从而使单一登录无效。 - prompt=none 则相反。 它确保不向用户显示任何交互式提示。 如果请求无法通过单一登录以无提示方式完成,则 Microsoft 标识平台将返回 interaction_required 错误。 - prompt=consent 在用户登录后触发 OAuth 同意对话框,要求用户向应用授予权限。 - prompt=select_account 将中断单一登录,提供帐户选择体验,列出会话或任何记住的帐户中的所有帐户,或者提供选择一起使用其他帐户的选项。 |
login_hint | 可选 | 可使用此参数预先填充用户登录页面的用户名和电子邮件地址字段。 应用在已经从前次登录提取 login_hint 可选声明后,可在重新身份验证时使用此参数。 |
domain_hint | 可选 | 如果包含,应用将跳过用户在登录页面上经历的基于电子邮件的发现过程,导致稍微更加流畅的用户体验。 例如,将其发送到其联合标识提供者。 应用可以在重新身份验证期间使用此参数,方法是从前次登录提取 tid。 |
code_challenge | 建议/必需 | 用于通过“用于代码交换的证明密钥”(PKCE) 来保护授权代码授予。 如果包含 code_challenge_method,则需要。 有关详细信息,请参阅 PKCE RFC。 目前建议将参数用于所有应用程序类型(公共和机密客户端),Microsoft 标识平台则要求使用授权代码流的单页应用使用此参数。 |
code_challenge_method | 建议/必需 | 用于为 code_challenge 参数编码 code_verifier 的方法。 此方法应为 S256,但是如果客户端不能支持 SHA256,则该规范允许使用 plain。 如果已排除在外,且包含了 code_challenge,则假定 code_challenge 为纯文本。 Microsoft 标识平台支持 plain 和 S256。 有关详细信息,请参阅 PKCE RFC。 使用授权代码流的单页应用需要此参数。 |
此时,系统会要求用户输入凭据并完成身份验证。 Microsoft 标识平台还将确保用户已同意 scope 查询参数中指定的权限。 如果用户未同意其中的任一权限,就让用户同意所需的权限。 有关详细信息,请参阅 Microsoft 标识平台中的权限和同意。
兑换访问令牌的代码:/oauth2/v2.0/token
https://login.microsoftonline.com/common/oauth2/v2.0/token
通过code换取accessToken:
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 Host: https://login.microsoftonline.com Content-Type: application/x-www-form-urlencoded client_id=11112222-bbbb-3333-cccc-4444dddd5555 &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read &code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr... &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F &grant_type=authorization_code &code_verifier=ThisIsntRandomButItNeedsToBe43CharactersLong &client_secret=sampleCredentia1s
获取 authorization_code 并获取用户授予的权限后,接下来可以兑换 code 以获取资源的 access_token。 通过向 /token 终结点发送 POST 请求来兑换 code
参数说明:
参数 | 必需/可选 | 说明 |
---|---|---|
tenant | 必需 | 请求路径中的 {tenant} 值可用于控制哪些用户可以登录应用程序。 有效值为 common 、organizations 、consumers 和租户标识符。 有关详细信息,请参阅终结点。 |
client_id | 必答 | Microsoft Entra 管理中心 - 应用注册页分配给你的应用的应用程序(客户端)ID。 |
scope | 可选 | 范围的空格分隔列表。 范围必须全部来自单个资源,以及 OIDC范围(profile 、openid 、email )。 有关详细信息,请参阅 Microsoft 标识平台中的权限和同意。 此参数是授权代码流的 Microsoft 扩展,旨在允许应用在令牌兑换期间声明其需要令牌的资源。 |
code | 必需的 | 在流的第一个阶段获取的 authorization_code 。 |
redirect_uri | 必需的 | 用于获取 authorization_code 的相同 redirect_uri 值。 |
grant_type | 必需 | 必须是授权代码流的 authorization_code 。 |
code_verifier | 建议 | 用于获取 authorization_code 的相同 code_verifier 。 如果在授权码授权请求中使用 PKCE,则需要。 有关详细信息,请参阅 PKCE RFC。 |
client_secret | 机密 Web 应用所需 | 在应用注册门户中为应用创建的应用程序机密。 请不要在本机应用或单页应用中使用应用程序机密,因为 client_secret 无法可靠地存储在设备或网页上。 可将 client_secret 安全地存储在服务器端的 Web 应用和 Web API 需要应用程序机密。 与此处讨论的所有参数一样,客户端机密在发送之前必须进行 URL 编码。 此步骤由 SDK 完成。 有关 URI 编码的详细信息,请参阅 URI 常规语法规范。 还支持根据 RFC 6749 在授权标头中提供凭据的基本身份验证模式。 |
获取用户信息
https://graph.microsoft.com/v1.0/me
通过accessToken获取登陆用户信息,并校验accessToken有效性
import requests user_info_url = "https://graph.microsoft.com/v1.0/me" headers = {'Authorization': f'Bearer {access_token}'} user_info_response = requests.get(user_info_url, headers=headers) user_info = user_info_response.json() print(user_info)
完整流程
const axios = require('axios'); const querystring = require('querystring'); // 替换以下占位符为你的实际值 const tenantId = '{tenant-id}'; const clientId = '{client-id}'; const clientSecret = '{client-secret}'; const redirectUri = '{redirect-uri}'; const authorizationCode = '{authorization-code}'; // Step 2: Exchange authorization code for tokens const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`; const tokenPayload = querystring.stringify({ grant_type: 'authorization_code', client_id: clientId, redirect_uri: redirectUri, code: authorizationCode, client_secret: clientSecret, }); axios.post(tokenUrl, tokenPayload, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }) .then(tokenResponse => { const accessToken = tokenResponse.data.access_token; // Step 3: Get user info using the access token const graphUrl = 'https://graph.microsoft.com/v1.0/me'; const config = { headers: { Authorization: `Bearer ${accessToken}`, }, }; return axios.get(graphUrl, config); }) .then(userInfoResponse => { console.log(JSON.stringify(userInfoResponse.data, null, 2)); }) .catch(error => { console.error('Error:', error); });
转载本站文章《Microsoft Entra(Azure ADD) MSAL库SSO OAuth2登录详解》,
请注明出处:https://www.zhoulujun.cn/html/tools/cloudServices/Azure/9290.html