Reactjs 在React中使用Httponly Cookie处理会话
当您从react中的HttpOnly Cookie获取令牌时,处理用户会话的最佳实践是什么 我的登录端点如下所示,如您所见,在cookie上设置了令牌:Reactjs 在React中使用Httponly Cookie处理会话,reactjs,security,authentication,jwt-auth,Reactjs,Security,Authentication,Jwt Auth,当您从react中的HttpOnly Cookie获取令牌时,处理用户会话的最佳实践是什么 我的登录端点如下所示,如您所见,在cookie上设置了令牌: @Post('login') @HttpCode(HttpStatus.OK) async login(@Ip() ipAddress, @Request() req, @Res() res: Response) { const auth = await this.basicAuthService.login(re
@Post('login')
@HttpCode(HttpStatus.OK)
async login(@Ip() ipAddress, @Request() req, @Res() res: Response) {
const auth = await this.basicAuthService.login(req.user, ipAddress);
const cookieOptions = setTokenCookie();
res.cookie('token', auth.token, { httpOnly: true });
res.cookie('refreshToken', auth.refreshToken, { httpOnly: true });
res.send(auth);
}
我还有另一个端点,它解码令牌以获取用户数据
@Get('user-data')
async getTokenPayload(@Request() req) {
if (!('token' in req.cookies)) {
throw new HttpException('Token was not provided', HttpStatus.NOT_FOUND);
}
const { token } = req.cookies;
return this.basicAuthService.getTokenPayload(token);
}
在前端,我像这样使用React中的API上下文,正如您所看到的,我从/user data
端点获取数据:
export const UserContext = createContext<UserContextState>(userContextValue);
export const UserProvider:FC<UserProviderProps> = ({ children }) => {
const [user, setUser] = useState<User>(userInitialValue);
useEffect(() => {
const getData = async () => {
const tokenDecoded = await getUserData();
setUser(tokenDecoded.user);
};
getData();
}, []);
return (
<UserContext.Provider value={{ user, setUser }}>
{ children }
</UserContext.Provider>
);
};
export const UserContext=createContext(userContextValue);
export const UserProvider:FC=({children})=>{
const[user,setUser]=useState(userInitialValue);
useffect(()=>{
const getData=async()=>{
const tokenDecoded=等待getUserData();
setUser(tokenDecoded.user);
};
getData();
}, []);
返回(
{儿童}
);
};
它工作正常,问题是每次浏览器刷新时都会发出请求,以获取用户数据并将其设置为react状态。我不确定这是否是一种好的做法,因为有时用户没有经过身份验证,而且显然,
/user data
请求返回一个错误。我不想将令牌存储在localStorage上或将HttpOnly设置为false。有更好的方法吗?据我所知,您有服务器端会话,比如说express session,我知道并且可以解释,但我相信这个概念与其他人是一样的
- 因此,据我所知,如果用户登录并进行会话时,cookie将在浏览器中设置,并且只有在满足到期日期的情况下才会删除,除此之外,cookie将保留在浏览器中。这意味着即使是在页面重新加载时,cookie也不会去任何地方
- 所以,从你所说的,我高度相信cookie没有在浏览器中设置,或者可能你只是错误地解释了,因为如果cookie已经设置,而且还没有过期,即使在页面重新加载时也应该存在
router.post('/api/login', (req, res)=>{
//Do all your logic and now below is how you would send down the cooki
//Note that "user" is the retrieved user when you were validating in logic
// So now you want to add user info to cookie so to validate in future
const sessionUser = {
id: user._id,
username: user.username,
email: user.email,
};
//Saving the info req session and this will automatically save in your mongoDB as configured up in sever.js(Server entry point)
request.session.user = sessionUser;
//Now we send down the session cookie to client
response.send(request.session.sessionID);
})
首先,您需要以下软件包
npm i快速会话连接mongodb会话
或添加快速会话连接mongodb会话
现在我们有了安装mongoStore和express会话中间件所需的软件包:
//Code in server.js/index.js (Depending on your server entry point)
import expressSession from "express-session";
import MongoDBStore from "connect-mongodb-session";
import cors from "cors";
const mongoStore = MongoDBStore(expressSession);
const store = new mongoStore({
collection: "userSessions",
uri: process.env.mongoURI,
expires: 1000,
});
app.use(
expressSession({
name: "SESS_NAME",
secret: "SESS_SECRET",
store: store,
saveUninitialized: false,
resave: false,
cookie: {
sameSite: false,
secure: process.env.NODE_ENV === "production",
maxAge: 1000,
httpOnly: true,
},
})
);
现在会话中间件已准备就绪,但现在您必须设置cors以接受您的ReactApp,以便传递cookie并通过服务器将其设置在其中
//Still you index.js/server.js (Server entry point)
app.use(
cors({
origin: "http://localhost:3000",
methods: ["POST", "PUT", "GET", "OPTIONS", "HEAD"],
credentials: true,
})
);
现在我们的中间件都已经安装好了,现在让我们看看您的登录路径
router.post('/api/login', (req, res)=>{
//Do all your logic and now below is how you would send down the cooki
//Note that "user" is the retrieved user when you were validating in logic
// So now you want to add user info to cookie so to validate in future
const sessionUser = {
id: user._id,
username: user.username,
email: user.email,
};
//Saving the info req session and this will automatically save in your mongoDB as configured up in sever.js(Server entry point)
request.session.user = sessionUser;
//Now we send down the session cookie to client
response.send(request.session.sessionID);
})
现在我们的服务器已经准备好了,但现在我们必须修复如何在客户端发出请求,以便该流能够100%工作:
//Code in server.js/index.js (Depending on your server entry point)
import expressSession from "express-session";
import MongoDBStore from "connect-mongodb-session";
import cors from "cors";
const mongoStore = MongoDBStore(expressSession);
const store = new mongoStore({
collection: "userSessions",
uri: process.env.mongoURI,
expires: 1000,
});
app.use(
expressSession({
name: "SESS_NAME",
secret: "SESS_SECRET",
store: store,
saveUninitialized: false,
resave: false,
cookie: {
sameSite: false,
secure: process.env.NODE_ENV === "production",
maxAge: 1000,
httpOnly: true,
},
})
);
下面的代码:React应用程序/您在处理登录时使用的任何应用程序
//So you will have all your form logic and validation and below
//You will have a function that will send request to server
const login = () => {
const data = new FormData();
data.append("username", username);
data.append("password", password);
axios.post("http://localhost:5000/api/user-login", data, {
withCredentials: true, // Now this is was the missing piece in the client side
});
};
现在有了所有这些,您现在将服务器会话cookie设置为httpOnly当您说它工作时,cookie是否在React应用程序中设置并标记为httpOnly?否,cookie在浏览器中设置并标记为httpOnly。另外,为了从cookie中获取数据,我在后端创建了一个新的端点对其进行解码,cookie在请求中发送,响应是用户数据,该响应我将其设置为React状态。您是否使用NodeJS制作此服务器端cookie?是的,在浏览器中设置我的应用cookie时使用nest.js,它们仅为HttpOnly,如果我刷新,它们仍然在那里。我存储在cookie中的是一个Jwt令牌,它包含使用API上下文将其设置为react状态所需的用户信息。因为我的cookie是HttpOnly,所以我无法在前端访问它,所以现在我请求对其进行解码并返回用户数据,然后将其设置为react状态。我认为这不是一个好做法,所以我想知道保存用户数据的最佳方法是什么(从作为HttpOnly存储在我的cookie中的jwt)在我的react State中,我认为这是一个复制品,但它没有答案,你必须理解httpOnly cookies背后的核心概念。这样做是为了避免客户端使用javaScript访问它,因为它会引起安全问题,所以当使用httpOnly cookies时,所有与会话相关的内容都留给服务器处理。因为,如果客户端能够访问该cookie,那么它就无法实现httpOnly cookie的目的。是的,我理解。我只是想知道这是否是最好的解决方案,正如我提到的那样。对于我来说,每次在前端刷新浏览器时都请求获取用户数据似乎有点奇怪。