我的问题是:
我有一个完整的网站,使用 react 构建,并通过 Nodejs 连接到该站点,基本上所有站点信息都来自服务器端。
对于聊天功能,无法使用服务器端,因为需要使用称为监听器的东西,在 React 中也需要配置 firebase 才能使监听器正常工作。对于聊天,您需要允许连接的用户发送消息,这不会向所有人开放。要知道谁连接了,您需要使用称为 auth 的选项。
我需要auth,对于 firebase 的规则,我只能允许连接的用户访问聊天室,而不是将规则开放给所有人。
当我在 firebase 中设置规则为 true 时,聊天功能可以正常工作,但我希望仅允许注册用户使用聊天功能,因此我进行了规则设置。
我遇到了以下错误:
Uncaught Error in snapshot listener: FirebaseError: Missing or insufficient permissions.
问题在于我已经通过服务器端进行连接,但需要以某种方式通过React进行连接。我还需要通过React进行连接以查看谁已连接,并且只允许已连接的用户使用聊天功能。需要通过React连接,因为只有通过React才能获得firebase提供的所有功能。如果直接通过React连接到firebase,才能获取授权。但是需要在React中连接聊天室。 (需要监听器,这样用户可以立即收到其他人发来的信息,并且需要授权以允许仅注册用户访问聊天室)
为了做到这一点,我需要通过React进行连接,并使用称为“auth”的东西来查看谁已连接。但整个网站本身都是围绕着通过nodejs登录构建的,在nodejs中不可能使用auth。 nodejs无法跟踪auth,它只返回JSON中的信息。
我不知道如何在React中启用与auth的连接,因为正如我所说,将所有连接传输到React将导致填充站点上的更改。但是,通过nodejs登录不允许使用auth,因为它是服务器端,我的服务器端仅返回JSON数据而不是像auth之类的功能。
我考虑过通过React和nodejs两次进行登录,但我担心这样做行不通,因为它可能会创建2个不同的令牌,并且只允许其中一个工作。
我尝试过其他解决方案,例如privateRoute,但仍然无济于事,因为必须以某种方式获取auth,以便知道谁已连接。如果有人可以帮我解决这个问题或提供解决方案,我会很高兴。我认为应该有一些方法可以解决这个问题。
如何告诉firebase一个注册用户想要访问聊天室?
迄今为止我所做的内容的代码:
通过nodejs登录
app.post('/login', login);
exports.login = (req, res) => {
const user = {
email: req.body.email,
password: req.body.password,
};
const { valid, errors } = validateLoginData(user);
if (!valid) return res.status(400).json(errors);
firebase
.auth()
.signInWithEmailAndPassword(user.email, user.password)
.then((data) => {
console.log(JSON.stringify(data));
return data.user.getIdToken();
})
.then((token) => {
db.collection('users')
.where("email", "==", user.email)
.get()
.then((data) => {
data.forEach((doc) => {
let userHandle = doc.data().handle;
db.collection("users")
.doc(userHandle)
.get()
.then((doc) => {
let user = doc.data();
db.collection('users').doc(userHandle)
.set(user)
.then(() => {
return res.json({ token: token});
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
}).catch((error) => {
console.error(error);
});
});
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code });
});
})
.catch((err) => {
console.error(err);
return res
.status(403)
.json({ general: "Wrong credentials, please try again" });
});
};
使用 nodejs 登录函数
export const loginUser = (userData, history) => (dispatch) => {
//userData contains mail and password
axios
.post('/login', userData)
.then((res) => {
setAuthorizationHeader(res.data.token);
//maybe add the auth here somehow
dispatch(getUserData());
dispatch
({
type: LOGIN_USER,
payload: res.data.handle
});
history.push('/');
})
.catch((err) => {
dispatch({
type: SET_ERRORS,
payload: err.response.data
});
});
};
React中的PrivateRoute
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
const PrivateRoute = ({component: Component, ...rest}) => {
return(
<Route {...rest} component={(props) => {
const user = localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')) : null;
if(user){
return <Component {...props} />
}else{
return <Redirect to={`/login`} />
}
}} />
)
}
export default PrivateRoute
React中的身份验证连接,但不包括聊天,我不确定如何处理聊天部分。
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import './App.css';
import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider';
import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
import jwtDecode from 'jwt-decode';
// Redux
import { Provider } from 'react-redux';
import store from './redux/store';
import { SET_AUTHENTICATED } from './redux/types';
import { logoutUser, getUserData } from './redux/actions/userActions';
// Components
import Navbar from './components/layout/Navbar';
import themeObject from './util/theme';
import AuthRoute from './util/AuthRoute';
import PrivateRoute from './util/PrivateRoute';
// Pages
import home from './pages/home';
import login from './pages/login';
import signup from './pages/signup';
import chat from './pages/chat';
import axios from 'axios';
const theme = createMuiTheme(themeObject);
axios.defaults.baseURL =
'https://europe-west1-projectdemourl-b123c.cloudfunctions.net/api';
const token = localStorage.FBIdToken;
if (token) {
const decodedToken = jwtDecode(token);
if (decodedToken.exp * 1000 < Date.now()) {
store.dispatch(logoutUser());
window.location.href = '/login';
} else {
store.dispatch({ type: SET_AUTHENTICATED });
axios.defaults.headers.common['Authorization'] = token;
store.dispatch(getUserData());
}
}
class App extends Component {
render() {
return (
<MuiThemeProvider theme={theme}>
<Provider store={store}>
<Router>
<Navbar />
<div className="container">
<Switch>
<Route exact path="/" component={home} />
<AuthRoute exact path="/login" component={login} />
<AuthRoute exact path="/signup" component={signup} />
<PrivateRoute path="/chat" exact component={chat} />
</Switch>
</div>
</Router>
</Provider>
</MuiThemeProvider>
);
}
}
export default App;
登陆Firebase,客户端
import firebase from "firebase/app";
import "firebase/firestore";
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_KEY,
authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
};
firebase.initializeApp(firebaseConfig);
export default firebase;
我用于聊天的功能,这些功能中我使用了Firebase。
export const getRealtimeUsers = (handle) => {
return async (dispatch) => {
const db = firebase.firestore();
const unsubscribe = db.collection("users")
.onSnapshot((querySnapshot) => {
db.collection('friends')
.get()
.then((data) => {
let friends = [];
data.forEach((doc) => {
if (doc.data().isFriends) {
if (doc.data().userHandleReceive == handle) {
friends.push(doc.data().userHandleSend);
}
else {
friends.push(doc.data().userHandleReceive);
}
}
});
const users = [];
querySnapshot.forEach(function (doc) {
if (doc.data().handle != handle && (friends.indexOf(doc.data().handle) > -1) ) {
users.push(doc.data());
}
});
})
.catch((err) => {
console.error(err);
});
});
return unsubscribe;
}
}
export const updateMessage = (msgObj) => {
return async dispatch => {
const db = firebase.firestore();
db.collection('conversations')
.add({
...msgObj,
isView: false,
createdAt: new Date()
})
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
}
}
export const getRealtimeConversations = (user) => {
return async dispatch => {
const db = firebase.firestore();
db.collection('conversations')
.where('user_uid_1', 'in', [user.uid_1, user.uid_2])
.orderBy('createdAt', 'asc')
.onSnapshot((querySnapshot) => {
const conversations = [];
querySnapshot.forEach(doc => {
if (
(doc.data().user_uid_1 == user.uid_1 && doc.data().user_uid_2 == user.uid_2)
||
(doc.data().user_uid_1 == user.uid_2 && doc.data().user_uid_2 == user.uid_1)
) {
conversations.push(doc.data())
}
});
dispatch({
type: userConstants.GET_REALTIME_MESSAGES,
payload: { conversations }
})
})
}
}
这是代码的主要部分,需要注意的是我需要在身份验证中添加loginUser函数的React选项。
我想澄清的是,我通过Nodejs创建了一个经过身份验证的用户,但React并未看到它的身份验证。
我只是漏掉了一些东西,在这里问题非常小,但我无法找出问题所在以及如何修复它。
console.log(req.body)
和 body-parser。你确定你的 req.body 不是空的吗? - Someone Special