Javascript 使用socket.io、passport.js next.js进行身份验证

Javascript 使用socket.io、passport.js next.js进行身份验证,javascript,node.js,passport.js,next.js,Javascript,Node.js,Passport.js,Next.js,我正在尝试重新进行身份验证。我用passport.js,特别是socket.io,拼凑了一个HTML mvp的后端代码 现在我已经做了前端,对于管理身份验证的最佳方法感到非常困惑 现在,用户注册了,我使用passport管理auth,并在mysql中保存详细信息。然后我使用socket.io在他们使用MVP时维护连接 例如,在脚本标签中用户页面的html上 document.addEventListener('DOMContentLoaded', () => {

我正在尝试重新进行身份验证。我用passport.js,特别是socket.io,拼凑了一个HTML mvp的后端代码

现在我已经做了前端,对于管理身份验证的最佳方法感到非常困惑

现在,用户注册了,我使用passport管理auth,并在mysql中保存详细信息。然后我使用socket.io在他们使用MVP时维护连接

例如,在脚本标签中用户页面的html上

document.addEventListener('DOMContentLoaded', () => {

                const urlParams = new URLSearchParams(window.location.search);
                const jwtUser = urlParams.get('t');
                localStorage.setItem('jwtUser', jwtUser)

                const $error = document.querySelector('#error');
                const $content = document.querySelector('#content');

                const socket = io.connect('wss://asdasd.ddaa', {
                    reconnection: true,
                    reconnectionDelay: 10000,
                    timeout: 300000,
                });
                socket.on('error', err => {
                    err = JSON.parse(err);
                    // console.log('error', err);
                    $content.classList.add('d-none');
                    $error.classList.remove('d-none');
                    $error.innerText = err.message;
                });

                socket.emit('login-jwt', { jwtUser: jwtUser }, response => {    socket.emit('magic.get', null, response => {
                $error.classList.add('d-none');

                if (response.items.length) {
                    $content.classList.remove('d-none');

                    const superdata = [];

                    .....
                        });
                    });
这是注册页面脚本

const socket = io.connect('wss://ddada.sadsad', {
                reconnection: true,
                reconnectionDelay: 10000,
                timeout: 300000,
            });

            document.querySelector('#form-signup').addEventListener('submit', e => {
                e.preventDefault();
                socket.emit('signup', { username: document.querySelector('#signup-username').value, password: document.querySelector('#signup-password').value }, response => {
                    alert(response.error ? response.error.message : response.message);
                });
            });
现在,我正在使用next.js,并使用一个util文件来尝试处理这个基于优秀样板文件的身份验证。我正试图用最好的方式来实现这个登录功能

import React, {
  useState,
  useEffect,
  useMemo,
  useContext,
  createContext,
} from "react";


import queryString from "query-string";
import fakeAuth from "fake-auth";

import { useUser, createUser, updateUser } from "./db";
import router from "next/router";

import PageLoader from "./../components/PageLoader";

import { getFriendlyPlanId } from "./prices";
import analytics from "./analytics";

// Whether to merge extra user data from database into auth.user
const MERGE_DB_USER = true;

// Whether to connect analytics session to user.uid
const ANALYTICS_IDENTIFY = false;

const authContext = createContext();

// Context Provider component that wraps your app and makes auth object
// available to any child component that calls the useAuth() hook.
export function ProvideAuth({ children }) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

// Hook that enables any component to subscribe to auth state
export const useAuth = () => {
  return useContext(authContext);
};

// Provider hook that creates auth object and handles state
function useProvideAuth() {
  // Store auth user object
  const [user, setUser] = useState(null);

  // Format final user object and merge extra data from database
  const finalUser = usePrepareUser(user);

  // Connect analytics session to user
  useIdentifyUser(finalUser);

  // Handle response from authentication functions
  const handleAuth = async (user) => {
    // Create the user in the database
    // fake-auth doesn't indicate if they are new so we attempt to create user every time
    await createUser(user.uid, { email: user.email });

    // Update user in state
    setUser(user);
    return user;
  };

  const signup = (email, password) => {
    return fakeAuth
      .signup(email, password)
      .then((response) => handleAuth(response.user));
  };

  const signin = (email, password) => {
    return fakeAuth
      .signin(email, password)
      .then((response) => handleAuth(response.user));
  };

  const signinWithProvider = (name) => {
    return fakeAuth
      .signinWithProvider(name)
      .then((response) => handleAuth(response.user));
  };

  const signout = () => {
    return fakeAuth.signout();
  };

  const sendPasswordResetEmail = (email) => {
    return fakeAuth.sendPasswordResetEmail(email);
  };

  const confirmPasswordReset = (password, code) => {
    // [INTEGRATING AN AUTH SERVICE]: If not passing in "code" as the second
    // arg above then make sure getFromQueryString() below has the correct
    // url parameter name (it might not be "code").

    // Get code from query string object
    const resetCode = code || getFromQueryString("code");
    return fakeAuth.confirmPasswordReset(password, resetCode);
  };

  const updateEmail = (email) => {
    return fakeAuth.updateEmail(email).then((rawUser) => {
      setUser(rawUser);
    });
  };

  const updatePassword = (password) => {
    return fakeAuth.updatePassword(password);
  };

  // Update auth user and persist to database (including any custom values in data)
  // Forms can call this function instead of multiple auth/db update functions
  const updateProfile = async (data) => {
    const { email, name, picture } = data;

    // Update auth email
    if (email) {
      await fakeAuth.updateEmail(email);
    }

    // Update auth profile fields
    if (name || picture) {
      let fields = {};
      if (name) fields.name = name;
      if (picture) fields.picture = picture;
      await fakeAuth.updateProfile(fields);
    }

    // Persist all data to the database
    await updateUser(user.uid, data);

    // Update user in state
    const currentUser = await fakeAuth.getCurrentUser();
    setUser(currentUser);
  };

  useEffect(() => {
    // Subscribe to user on mount
    const unsubscribe = fakeAuth.onChange(async (response) => {
      if (response.user) {
        setUser(response.user);
      } else {
        setUser(false);
      }
    });

    // Unsubscribe on cleanup
    return () => unsubscribe();
  }, []);

  return {
    user: finalUser,
    signup,
    signin,
    signinWithProvider,
    signout,
    sendPasswordResetEmail,
    confirmPasswordReset,
    updateEmail,
    updatePassword,
    updateProfile,
  };
}

// Format final user object and merge extra data from database
function usePrepareUser(user) {
  // Fetch extra data from database (if enabled and auth user has been fetched)
  const userDbQuery = useUser(MERGE_DB_USER && user && user.uid);

  // Memoize so we only create a new object if user or userDbQuery changes
  return useMemo(() => {
    // Return if auth user is null (loading) or false (not authenticated)
    if (!user) return user;

    // Data we want to include from auth user object
    let finalUser = {
      uid: user.uid,
      email: user.email,
      name: user.name,
      picture: user.picture,
    };

    // Include an array of user's auth providers, such as ["password", "google", etc]
    // Components can read this to prompt user to re-auth with the correct provider
    finalUser.providers = [user.provider];

    // If merging user data from database is enabled ...
    if (MERGE_DB_USER) {
      switch (userDbQuery.status) {
        case "idle":
          // Return null user until we have db data to merge
          return null;
        case "loading":
          return null;
        case "error":
          // Log query error to console
          console.error(userDbQuery.error);
          return null;
        case "success":
          // If user data doesn't exist we assume this means user just signed up and the createUser
          // function just hasn't completed. We return null to indicate a loading state.
          if (userDbQuery.data === null) return null;

          // Merge user data from database into finalUser object
          Object.assign(finalUser, userDbQuery.data);

          // Get values we need for setting up some custom fields below
          const { stripePriceId, stripeSubscriptionStatus } = userDbQuery.data;

          // Add planId field (such as "basic", "premium", etc) based on stripePriceId
          if (stripePriceId) {
            finalUser.planId = getFriendlyPlanId(stripePriceId);
          }

          // Add planIsActive field and set to true if subscription status is "active" or "trialing"
          finalUser.planIsActive = ["active", "trialing"].includes(
            stripeSubscriptionStatus
          );

        // no default
      }
    }

    return finalUser;
  }, [user, userDbQuery]);
}

// A Higher Order Component for requiring authentication
export const requireAuth = (Component) => {
  return (props) => {
    // Get authenticated user
    const auth = useAuth();

    useEffect(() => {
      // Redirect if not signed in
      if (auth.user === false) {
        router.replace("/auth/signin");
      }
    }, [auth]);

    // Show loading indicator
    // We're either loading (user is null) or we're about to redirect (user is false)
    if (!auth.user) {
      return <PageLoader />;
    }

    // Render component now that we have user
    return <Component {...props} />;
  };
};

// Connect analytics session to current user.uid
function useIdentifyUser(user) {
  useEffect(() => {
    if (ANALYTICS_IDENTIFY && user) {
      analytics.identify(user.uid);
    }
  }, [user]);
}

const getFromQueryString = (key) => {
  return queryString.parse(window.location.search)[key];
};
和实用程序文件

import fakeAuth from "fake-auth";

export function apiRequest(path, method = "GET", data) {
  const accessToken = fakeAuth.getAccessToken();

  return fetch(`/api/${path}`, {
    method: method,
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${accessToken}`,
    },
    body: data ? JSON.stringify(data) : undefined,
  })
    .then((response) => response.json())
    .then((response) => {
      if (response.status === "error") {
        // Automatically signout user if accessToken is no longer valid
        if (response.code === "auth/invalid-user-token") {
          fakeAuth.signout();
        }

        throw new CustomError(response.code, response.message);
      } else {
        return response.data;
      }
    });
}

// Create an Error with custom message and code
export function CustomError(code, message) {
  const error = new Error(message);
  error.code = code;
  return error;
}
如果需要,这是express服务器

现在,我究竟如何用next.js和这个设置系统复制socket.io和html页面的功能?Firebase auth可能更容易上钩

https://codesandbox.io/s/relaxed-http-75fxf?file=/next.config.js
这是一个简单的例子-干杯

const io = require('socket.io')(server, { wsEngine: 'ws' });

const sharedsession = require('express-socket.io-session');

server.listen(config.serverParams.port, config.serverParams.address, () => {
    console.log(`Server running at http://${server.address().address}:${server.address().port}`);
});

/* DATABASE */
global.db = mysql.createConnection(config.db);
db.connect();
/* DATABASE */

/* SESSION */
const sessionStore = new ExpressMysqlSessionStore(config.sessionStore, db);
const session = expressSession({
    ...config.session,
    store: sessionStore,
});
app.use(session);
/* SESSION */

    //can reaplce * with website we want to allow access
    res.header('Access-Control-Allow-Origin', 'dfsfsf24f2');
  next();
  });

app.get([
    '/axsxsa',
    '/asxasx',
    '/asxasx',
], (req, res) => res.sendFile(path.join(`${config.frontendDir}${req.path}.html`)));

io.use(sharedsession(session, {
    autoSave: true
}));

io.on('connection', socket => {

    socket.use((packet, next) => {
        if (packet[0]) {
            console.log('METHOD:', packet[0]);
            const sessionData = socket.handshake.session.user;
            console.log(sessionData)
            const noSessionNeed = [ 'login', 'signup', 'checkAuth' ].includes(packet[0]);
            let error;
            if ( ! sessionData && ! noSessionNeed) error = { code: -1, message: 'You need to login in extension!' };
            if (error) return next(new Error(JSON.stringify(error)));
            else next();
        }
    });

    const auth = require('./auth')(socket);
    socket.on('checkAuth', auth.checkAuth);
    socket.on('login', auth.login);
    socket.on('signup', auth.signup);
    socket.on('logout', auth.logout);

    const users = require('./users')(socket);
    socket.on('users.get', users.get);

    const sentiment = require('./sentiment')(socket);
    socket.on('sentiment.get', sentiment.get);
    socket.on('sentiment.set', sentiment.set);

    socket.on('disconnect', () => {

    });

});
https://codesandbox.io/s/relaxed-http-75fxf?file=/next.config.js