Reactjs 在React中使用Httponly 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

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

我的登录端点如下所示,如您所见,在cookie上设置了令牌:

 @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已经设置,而且还没有过期,即使在页面重新加载时也应该存在

因此,如果您使用NodeJS作为后端,下面将介绍如何使用react应用程序处理express会话,并在用户登录并将会话保存到mongodb中后在浏览器中设置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的目的。是的,我理解。我只是想知道这是否是最好的解决方案,正如我提到的那样。对于我来说,每次在前端刷新浏览器时都请求获取用户数据似乎有点奇怪。