在React中使用Httponly Cookies处理会话 [英] Handling Sessions with Httponly Cookies in React

查看:396
本文介绍了在React中使用Httponly Cookies处理会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当您从HttpOnly cookie中获取令牌时,处理用户会话的最佳实践是什么?

What's the best practice handling user session when you get your token from HttpOnly cookies in react?

我的登录端点如下所示,并且您可以看到在cookie上设置了令牌:

My login endpoint looks like this and as you can see token is set on cookies:

 @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);
    }

我还有另一个端点,该端点解码令牌以获取用户数据

And also I have another endpoint which decodes a token in order to get user Data

 @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);
    }

在FrontEnd上,我像这样从React使用API​​ Context,正如您所看到的,我正在从/user-data端点获取数据:

On FrontEnd I'm using API Context from React like this, and as you can see I'm fetching data from the /user-data endpoint:

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>
  );
};

可以正常工作,问题是每次浏览器刷新时都会发出一个请求,以获取用户数据并将其设置为反应状态.我不确定这是否是一个好习惯,因为有时用户未通过身份验证,并且显然/user-data请求返回错误.我不想将令牌存储在localStorage上或将HttpOnly设置为false.有更好的方法吗?

It's working ok, the problem is a request is made every time the browser refreshes in order to get the users data and set it on the react state. I'm not sure whether this is a good practice, since sometimes user is not authenticated and obviously that /user-data request returns an error. I don't want to store the token on localStorage or set HttpOnly as false. Is there a better way to do it?

推荐答案

据我了解,您有服务器端会话,例如可以说 express-session ,我了解并可以解释,但是我相信其他人也一样.

From what I understand is your having server side session lets say for example express-session that which I know of and can explain but I believe that concept is the same with others.

  • 因此,据我了解,如果用户登录并进行会话,则将在浏览器中设置cookie,并且仅在满足该条件后才删除该cookie.会留在那里.这意味着即使在页面上重新加载,该Cookie 也永远不会消失.

  • So from what I understand is if when the user is logged in and a session is made that cookie is to be set in browser and will only be removed only if the expiration date has been met besides that then that cookie will stay there. Meaning that even on page reload that cookie will never go anywhere.

因此,我非常相信您所说的是cookie没有在浏览器中设置,或者您可能只是在解释不正确,因为如果cookie被设置并且即使在页面重新加载时也没有过期,应该在那里

So I am to highly believe from what you saying that the cookie is not getting set in browser or maybe you just mis-explained, cause if the cookie is getting set and not yet expired even on page reload should be there

因此,如果您在下面使用NodeJS作为后端,则是有关如何使用react app处理express-session以及如何在用户登录后将cookie设置在浏览器中并将其保存在mongodb中的实现.进行会话的情况下

首先,您需要以下软件包

npm i express-session connect-mongodb-session或yarn添加express-session connect-mongodb-session

npm i express-session connect-mongodb-session or yarn add express-session connect-mongodb-session

现在,我们有了设置mongoStore和express-session中间件所需的软件包:

//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%正常工作:

下面的代码:React App/无论您使用哪种登录习惯

//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

这篇关于在React中使用Httponly Cookies处理会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆