我目前正在尝试使用 React 客户端设置 Node/Express 应用程序以与之交互。我设置了护照来处理 JWT 身份验证。当用户登录时,我验证电子邮件/密码。然后我设置cookie:
res.cookie('jwt', token, { httpOnly: true, secure: false });
我看到令牌在响应标头中传回,但是当我在开发人员工具 > 应用程序 > Cookie 下检查 Chrome 浏览器的 cookie 时,我看到一个空 cookie。我做错了什么以及如何在后续请求的响应标头中发送 jwt?
服务器/App.js
const app = express()
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.post('/login', (req, res) => {
passport.authenticate('local', { session: false }, (error, user) => {
if (error || !user) {
res.status(400).json({ error });
}
// Construct JWT payload
const payload = {
email: user.email,
expires: Date.now() + parseInt(process.env.JWT_EXPIRATION_MS),
};
// Assign payload to req.user
req.login(payload, {session: false}, (error) => {
if (error) {
res.status(400).send({ error });
}
// Generate a signed JWT
const token = jwt.sign(JSON.stringify(payload), process.env.JWT_SECRET);
// Assign JWT to cookie
res.cookie('jwt', token, { httpOnly: true, secure: false });
res.status(200).send({ email: user.email });
});
})(req, res);
});
客户端/LoginModal.js
handleLogin = async () => {
const { name, email, password } = this.state
try{
const res = await axios.post('http://localhost:8080/login', {
email: email,
password: password,
})
if(res.status == 200){
console.log("Logged in")
console.log(res)
}
} catch (err) {
console.log(err)
}
}
编辑:我当前的解决方法是将令牌作为有效负载的一部分发送。然后,我的反应客户端从有效负载中获取令牌并将其存储在浏览器的 cookie 中。有没有办法避免这种解决方法(例如见下文)?
服务器
res.status(200).send({ email: user.email, jwt: token });
客户
if(res.status == 200){
cookies.set('jwt', res.data.jwt)
cookies.set('email', res.data.email)
}
在调用 axis.post() 时,您必须传递
{withCredentials: true, credentials: 'include'}
作为第二个参数,只有这样您的浏览器才会设置 cookie。
对我有用的是在 cors 包中设置
app.use(cors({ origin: true, credentials: true }))
。从后端获取时还设置withCredentials: true, credentials: 'include'
您已设置 cookie,并启用了 httpOnly 标志。大多数现代浏览器都通过开发人员工具限制对此类 cookie 的读取访问。您可以在此处阅读更多相关信息。
如果您想在开发环境中查看 cookie 的内容,请将 httpOnly 设置为 false。
我发现这个解决方案适用于本地开发和生产(以及 LAN 访问,例如,当您通过 LAN IP 地址访问网站时,如
http://192.168.xxx.xxx:<port>
):
// Set CORS options
const cors = require(`cors`)
const whitelist = [
'http://localhost:<application port>', // not https
'https://yourprod.ip.address.com' // must be https!
'http://<your local IP>:<port>', // optional, LAN access
// ...
]
const corsOptions = {
credentials: true,
origin: (origin, callback) => {
// `!origin` allows server-to-server requests (ie, localhost requests)
if(!origin || whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error("Not allowed by CORS: "+ origin))
}
},
optionsSuccessStatus: 200
}
app.use(cors(corsOptions))
然后在身份验证端点上:
// Set Cookie
const cookieContent = 'this is a cookie'
const cookieOptions = {
httpOnly: true, // safety, does not allow cookie to be read in the frontend javascript
maxAge: 24*3600*1, // cookie age in seconds
sameSite: 'Strict' // works for local development
}
if(process.env.NODE_ENV === 'production') {
// these options work on a https server
cookieOptions.secure = true
cookieOptions.sameSite= 'None'
}
res.cookie(
'cookie-tag',
refreshToken,
cookieOptions
)
res.json(cookieContent)
您必须将请求 post 更改为 get。