我正在尝试为我公司的网站创建一个登录系统,并在成功登录后以 cookie 的形式发送刷新令牌。在互联网和 SO 中搜索类似问题后,我有一个可以在本地主机中工作的解决方案,但我无法让它在生产中工作。这是我在生产中遇到的错误:
Access to fetch at 'https://my-linux-api.azurewebsites.net/my-site/login' from origin 'https://www.my-site.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
这真是让我费尽心思,因为“Access-Control-Allow-Origin”标头的值绝对不是“*”。这是我在 Node JS api 中的路线:
router.post("/my-site/login", function(req, res) {
var email = req.body.Email;
var password = req.body.Password;
var connection = new Connection(config);
var query = "SELECT * FROM dbo.Users WHERE Email = @email"
const request = new Request(query,
function(err) {
connection.close();
if (err) {
console.log(err);
res.send([]);
}
}
);
request.addParameter('email', TYPES.VarChar, email);
var result = [];
connection.connect((err) => {
if (err) {
console.log(err);
res.send(err);
}
else
{
request.on('row', function(columns) {
var col = []
columns.forEach((column) => {
col.push(column.value);
});
result.push(col);
});
request.on('doneProc', function(rowCount) {
if (result.length > 0) {
if (result[0][4] == password) {
if (result[0][8] !== 0) {
result[0].splice(4, 1);
const accessPayload = ({ User: result[0], Type: "Authentication" })
const accessToken = jwt.sign(accessPayload, process.env.secretKey, { expiresIn: 86400 });
const refreshPayload = ({ User: result[0][0], Type: "Refresh" })
const refreshToken = jwt.sign(refreshPayload, process.env.secretKey, { expiresIn: 172800 });
res.header('Access-Control-Allow-Origin', "https://www.my-site.com");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Authorization', `Bearer ${accessToken}`);
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'Lax',
path: "/"
})
res.setHeader('Content-Type', 'application/json');
res.json({ success: true, message: "Authorization Successful" });
}
else {
res.sendStatus(403)
}
}
else {
res.sendStatus(401);
}
}
else {
res.sendStatus(401)
}
})
request.on('requestCompleted', (rowCount, more)=> {
connection.close();
})
connection.execSql(request);
}
})
});
如您所见,我已将“Access-Control-Allow-Origin”标头设置为我的网站名称。我已经检查并仔细检查以确保没有尾随斜杠。
另外,我没有在路线中设置标头,而是尝试使用 cors 包,并将其用作我的路线的参数之一,按照文档:
const cors = require('cors');
const corsOptions = {
origin: 'https://www.my-site.com',
credentials: true,
};
router.post("/solutions/login", cors(corsOptions), function(req, res) { ....
我看到有些人说这样的错误是转移注意力,实际问题在其他地方,但事实上,当我将标头设置为“http://localhost:3000”时,它在本地工作,这让我相信没有其他问题。
这是前端代码,供后代使用:
export const Login = (email: string, password: string, context: any) =>
new Promise(async (resolve, reject) => {
var formData = new FormData();
formData.append('Email', email);
formData.append('Password', password);
await fetch(url + "my-site/login", {
method: 'POST',
credentials: 'include',
body: formData
})
.then((res: any) => {
let rawToken = res.headers.get("authorization").split(" ")[1];
var accessToken = jwt.decode(rawToken);
context.setUser(accessToken.User);
context.setIsAuthenticated(true);
localStorage.setItem(
"authorization",
rawToken
)
if (localStorage.getItem("theme") == null) {
localStorage.setItem("theme", "light");
}
resolve("Success")
})
.catch((err) => {
console.log(err);
if (err.response.status == 403) {
reject(403);
} else if (err.response.status == 401) {
reject(401);
} else {
reject("Error, please try again later");
}
})
});
我不明白如果 CORS 使得这样做如此困难,那么如何约定将刷新令牌存储为 cookie。
提前谢谢您
您在 /my-site/login 上发了帖子,但 cors 已配置为路由 /solutions/login,这是正确的吗?
而且,如果你想实现 cors,请将其添加为每个路由的中间件,如下所示:
const express = require('express');
const cors = require('cors');
const corsOptions = {
origin: 'https://www.example.com',
optionsSuccessStatus: 200,
};
const app = express();
app.use(cors(corsOptions));