如何使用 MSAL 身份验证和 Azure 函数验证用户电子邮件并检索全名

问题描述 投票:0回答:1

我正在开发一个用户使用 MSAL 身份验证登录的应用程序,并且在注册过程中,我已授予 Microsoft Graph API 的

user.ReadBasic.All
权限范围。现在,我需要验证提供的用户电子邮件(登录用户和登录用户提供的用于验证的电子邮件不同)是否属于同一租户,如果验证通过,则检索他们的全名。

这是我目前的方法:

  • 前端:用户使用 MSAL 身份验证登录。
  • 后端(Azure Function Endpoint API):我收到要验证的电子邮件以及请求中的访问令牌。然后我解码令牌以提取用户的电子邮件。
  • 接下来,我将提供的电子邮件的域与从解码的令牌中提取的域进行比较。如果它们匹配,我认为电子邮件已验证。

但是,这种方法仅验证电子邮件域是否与租户匹配,这并不能保证电子邮件属于实际用户。相反,我需要确保电子邮件属于租户内的有效用户并检索他们的全名。

任何人都可以指导我如何实现这一目标吗?具体来说,如何使用 MSAL 身份验证和 Azure Functions 验证用户的电子邮件并检索其全名?

以下是我的代码,其中我删除了比较和 jwt 解码逻辑。

module.exports = async function (context, req) {
    const tenantId = "YOUR_TENANT_ID"; 

    if (req.method === 'POST') {
        try {
            const { email } = req.body;
            const token = req.headers.authorization;

            if (!token || !email) {
                context.res = {
                    status: 400,
                    body: "Token in the 'Authorization' header and email in the request body are required."
                };
                return;
            }
            const bearerToken = token.split(' ')[1];

            // we decode jwt token to get tenantid and email

            if (!decoded || decoded.tid !== tenantId) {
                context.res = {
                    status: 403,
                    body: JSON.stringify({ error: 'Unauthorized: Invalid token or tenant' })
                };
                return;
            }

            const userEmail = decoded.preferred_username;
            if (typeof userEmail !== 'string' || typeof email !== 'string') {
                context.res = {
                    status: 400,
                    body: JSON.stringify({ error: 'Invalid email format' })
                };
                return;
            }

            // we check email domain comparison here 

            if (providedDomain !== tokenDomain) {
                context.res = {
                    status: 400,
                    body: JSON.stringify({ error: 'Email does not match the tenant. Verification failed.' })
                };
                return;
            }
            context.res = {
                status: 200,
                body: JSON.stringify({ message: 'Email matches the tenant. Verification successful.' })
            };

        } catch (error) {
            context.log.error('Token verification error:', error.message);
            context.res = {
                status: 401,
                body: JSON.stringify({ error: 'Invalid token' })
            };
        }
    } else {
        context.res = {
            status: 405,
            body: "Method Not Allowed"
        };
    }
};

任何帮助或建议将不胜感激。谢谢!

我想做的就是创建一个 Azure 函数 API,当来自同一租户的登录用户发送验证其他电子邮件的请求时,该 API 会检查电子邮件是否有效(以便用户可以排除任何类型的未验证电子邮件)公司内部注册)。

javascript azure azure-active-directory azure-functions azure-ad-msal
1个回答
0
投票

您需要向Graph API发出请求来检索用户的基本资料。您需要比较的字段是

mail

如果解码令牌中的电子邮件地址是用户的电子邮件别名,并且您希望允许使用电子邮件别名,则需要

User.Read.All
权限。这将允许您检索 full 配置文件,其中包含
proxyAddresses
数组。您需要从返回值的开头删除“SMTP:”部分,或者将“SMTP:”添加到比较中令牌的电子邮件开头。

这里有一些用于检索用户个人资料的代码:

const msal = require('@azure/msal-node');
const https = require('https');

// MSAL configuration
const msalConfig = {
    auth: {
        clientId: 'your_client_id',
        authority: 'https://login.microsoftonline.com/your_tenant_id',
        clientSecret: 'your_client_secret'
    }
};

const cca = new msal.ConfidentialClientApplication(msalConfig);

module.exports = async function (context, req) {
    const userEmail = req.query.email; // Get user's email address from request query

    if (!userEmail) {
        context.res = {
            status: 400,
            body: 'User email address is required'
        };
        return;
    }

    // Acquire a token for the Microsoft Graph API
    const tokenRequest = {
        scopes: ['https://graph.microsoft.com/.default']
    };

    try {
        const tokenResponse = await cca.acquireTokenByClientCredential(tokenRequest);

        // Microsoft Graph API endpoint for specific user profile
        const graphApiEndpoint = `https://graph.microsoft.com/v1.0/users/${userEmail}`;

        const options = {
            hostname: 'graph.microsoft.com',
            path: `/v1.0/users/${userEmail}`,
            method: 'GET',
            headers: {
                'Authorization': `Bearer ${tokenResponse.accessToken}`
            }
        };

        const req = https.request(options, (res) => {
            let data = '';

            res.on('data', (chunk) => {
                data += chunk;
            });

            res.on('end', () => {
                const userProfile = JSON.parse(data);
                context.res = {
                    body: {
                        id: userProfile.id,
                        displayName: userProfile.displayName,
                        givenName: userProfile.givenName,
                        surname: userProfile.surname,
                        mail: userProfile.mail
                    }
                };
            });
        });

        req.on('error', (error) => {
            context.res = {
                status: 500,
                body: error.message
            };
        });

        req.end();
    } catch (error) {
        context.res = {
            status: error.response ? error.response.status : 500,
            body: error.response ? error.response.data : 'Internal Server Error'
        };
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.