我有一个带有 NodeJS 后端和 React 前端的应用程序,我想为其实现 Azure SSO。由于前端是由后端提供服务的,因此想要登录应用程序的用户会被后端重定向到前端的登录页面。当用户单击登录页面上的相关按钮时,应打开 Azure 身份验证页面,登录后应将他们重定向回我的应用程序。但是,我在 API 端收到错误,如下所示。
访问 XMLHttpRequest 'https://login.microsoftonline.com/xxx/oauth2/v2.0/authorize?client_id={clientid}1&response_type=code&redirect_uri=http:%2F%2Flocalhost:3000%2Fauth%2Fcallback&response_mode=query&scope= https:%2F%2Fgraph.microsoft.com%2F.default+offline_access'(从'http://localhost:3000/api/auth/sso-login'重定向)来自原点'http://localhost:3000' 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。
我的API代码是
const params = new URLSearchParams({
client_id: CLIENT_ID,
response_type: 'code',
redirect_uri: REDIRECT_URI,
response_mode: 'query',
scope: 'https://graph.microsoft.com/.default offline_access'
});
res.redirect(`${authorizeUrl}?${params.toString()}`);
我创建了一个简单的nodejs应用程序,具有相同的逻辑,没有前端,它工作没有问题。
app.get('/login', (req, res) => {
const params = new URLSearchParams({
client_id: CLIENT_ID,
response_type: 'code',
redirect_uri: REDIRECT_URI,
response_mode: 'query',
scope: 'https://graph.microsoft.com/.default offline_access'
});
res.redirect(`${authorizeUrl}?${params.toString()}`);
});
app.get('/auth/callback', async (req, res) => {
const { code } = req.query;
if (!code) {
return res.status(400).send('Authorization code not found.');
}
try {
const response = await axios.post(tokenUrl, new URLSearchParams({
client_id: CLIENT_ID,
scope: 'https://graph.microsoft.com/.default',
code,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code',
client_secret: CLIENT_SECRET
}));
const accessToken = response.data.access_token;
res.send(`Access Token: ${accessToken}`);
} catch (error) {
res.status(500).send(`Error exchanging code: ${error.message}`);
}
});```
我通过将 CORS 添加到后端 (Node.js) 代码解决了该问题。现在,想要登录应用程序的用户已成功被后端重定向到前端的登录页面,并检索了访问令牌。
这是 GitHub 存储库中的完整代码。
后端/index.js :
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
app.use(cors());
app.use(express.json());
const tokenUrl = `https://login.microsoftonline.com/${process.env.TENANT_ID}/oauth2/v2.0/token`;
app.get('/api/auth/sso-login', (req, res) => {
const params = new URLSearchParams({
client_id: process.env.CLIENT_ID,
response_type: 'code',
redirect_uri: process.env.REDIRECT_URI,
response_mode: 'query',
scope: 'https://graph.microsoft.com/.default offline_access',
});
const loginUrl = `https://login.microsoftonline.com/${process.env.TENANT_ID}/oauth2/v2.0/authorize?${params.toString()}`;
res.redirect(loginUrl);
});
app.post('/api/auth/exchange-token', async (req, res) => {
const { code } = req.body;
if (!code) {
return res.status(400).json({ error: 'Authorization code not provided' });
}
try {
const response = await axios.post(tokenUrl, new URLSearchParams({
client_id: process.env.CLIENT_ID,
scope: 'https://graph.microsoft.com/.default',
code,
redirect_uri: process.env.REDIRECT_URI,
grant_type: 'authorization_code',
client_secret: process.env.CLIENT_SECRET,
}));
const accessToken = response.data.access_token;
res.json({ accessToken });
} catch (error) {
res.status(500).json({ error: `Error exchanging code: ${error.message}` });
}
});
const PORT = 4000;
app.listen(PORT, () => {
console.log(`Backend running on http://localhost:${PORT}`);
});
.env:
CLIENT_ID=<Client_ID>
CLIENT_SECRET=<Client_Secret>
TENANT_ID=<tenant_ID>
REDIRECT_URI=http://localhost:3000/auth/callback
前端/Login.js :
import React from 'react';
const Login = () => {
const handleLogin = () => {
window.location.href = `${process.env.REACT_APP_BACKEND_URL}/api/auth/sso-login`;
};
return (
<div>
<h2>Login Page</h2>
<button onClick={handleLogin}>Login with Azure</button>
</div>
);
};
export default Login;
前端/.env:
REACT_APP_CLIENT_ID=<client_ID>
REACT_APP_TENANT_ID=<tenant_ID>
REACT_APP_REDIRECT_URI=http://localhost:3000/auth/callback
REACT_APP_BACKEND_URL=http://localhost:4000
我已在 Azure AD 应用程序的重定向 URI 中的 Web 下添加了以下 URL,如下所示。
http://localhost:3000/auth/callback
后端输出:
我成功运行了后端(Node.js)应用程序。当我在浏览器中打开下面的 URL 时,它会将我重定向到登录页面,然后我使用我的帐户登录,如下所示:
http://localhost:4000/api/auth/sso-login
登录后,我收到了授权码,如下图:
我复制了授权码并在POST请求中使用它,如下所示。
我使用 authorization_code 发送了 POST 请求并收到了 访问令牌,如下所示。
http://localhost:4000/api/auth/exchange-token
{
"code": "<authorization_code>"
}
前端输出:
我成功运行了前端 (React.js) 应用程序并使用 Login with Azure 按钮登录。
登录后,我检索到了访问令牌,如下所示。