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