簡體   English   中英

使用 auth 知道用戶已登錄

[英]Using auth to know that a user is logged in

我的問題是這樣的:

我有一個用 react 構建的整個站點,我通過 Nodejs 連接到該站點,該站點的所有信息基本上都是從服務器端獲取的。

對於聊天,不可能使用服務器端,因為您需要一個稱為偵聽器的東西,對於偵聽器,您還需要在 React 中配置 firebase 並且偵聽器將起作用,對於聊天,您需要允許連接的用戶發送消息,不會對所有人開放。 要知道誰已連接,您需要使用名為 auth 的選項。

我需要身份驗證,對於 firebase 中的規則,我將只能允許連接的用戶訪問聊天,而不是讓規則對所有人開放。

當我將 firebase 中的規則設置為 true 時,聊天工作正常,但我希望只有注冊用戶才能使用聊天,我制定了規則。 在此處輸入圖像描述

我收到以下錯誤:

Uncaught Error in snapshot listener: FirebaseError: Missing or insufficient permissions.

問題是我已經通過服務器端連接,但還需要通過反應以某種方式連接,我還需要通過反應連接以查看誰已連接,並且僅對於那些已連接的人我想允許聊天用過的。 需要通過反應連接,因為只有通過反應我才能獲得 firebase 必須提供的所有功能。 只有通過react直接連接到firebase才能獲得auth,但是要求在react中我也會連接聊天。 (需要監聽器,因為這樣用戶可以立即收到某人發給他的消息,並且需要 auth 只允許注冊用戶訪問聊天)

為此,我需要通過 react 進行連接,並使用名為 auth 的東西來查看誰已連接。 但是整個站點本身是圍繞通過nodejs登錄而構建的,並且在nodejs中無法使用auth。 nodejs無法跟蹤auth,nodejs最終只返回JSON中的信息。

我不知道如何在react中啟用帶有auth的連接,因為我說的,將所有連接轉移到react中,會拖動以填充站點上的更改,但是通過nodejs登錄不允許使用auth,因為它是服務器端,所以我的服務器端只返回 JSON 數據,而不是像 auth 這樣的功能。

我正在考慮通過 react 和 nodejs 進行登錄時間,但我擔心它不會工作,因為它可能會創建 2 個不同的令牌並且只允許其中一個工作。

我曾嘗試過其他解決方案,例如 privateRoute,但它仍然無濟於事,因為必須以某種方式獲得身份驗證,這允許知道誰連接了。 如果有人可以幫助我或為我提供解決方案,我會很高興,我認為應該有一些可以做的事情並解決問題。

我如何告訴 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登錄function

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

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

響應連接的身份驗證,但不是聊天,聊天我不知道該怎么做

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

這是代碼的主要部分,另一個注意我需要在 auth的 react 選項中添加 loginUser function

我想澄清一下,我創建了一個通過 Nodejs 進行身份驗證的用戶,但 React 沒有看到它經過身份驗證。

我只是在這里遺漏了一些東西,問題非常非常小,但我無法弄清楚它在哪里,以及如何解決它

你的推理有幾個缺陷,你的代碼有幾個錯誤。

從根本上說:為什么要同時在服務器端和客戶端登錄?

如果您希望您的用戶登錄到您的數據庫進行讀取和/或寫入,您可以在客戶端執行此操作,也可以在服務器端執行此操作。 兩者都提供幾乎相同的選項。

在服務器和客戶端上都這樣做沒有多大意義。 引出了一個問題:為什么你要兩者都做?...

解決方案:

既然您在 html 頁面中收集用戶的登錄信息,為什么不在客戶端也立即登錄用戶呢?

以這個簡單的 HTML 為例,它有兩個輸入並加載三個 firebase 腳本:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="https://www.gstatic.com/firebasejs/8.4.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.4.1/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.4.1/firebase-firestore.js"></script>
</head>
<body>
    <input name="email" id="email" type="text">
    <input name="password" id="password" type="text">
    <button type="button" id="login">Login</button>
    <script src="index.js"></script>
</body>
</html>

在同一文件夾中添加ìndex.js文件:

var firebaseConfig = {
    apiKey: "AIzaSyAg2{.....}z7ObRoXg-goy9jc",
    authDomain: "s{.....}3.firebaseapp.com",
    projectId: "st{.....}40f63",
    storageBucket: "stacksh{.....}pspot.com",
    messagingSenderId: "537{.....}09",
    appId: "1:537{.....}04409:web:2{.....}7a6b67c14fa48"
};
firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
/* We listen for button click and then log in the user */
var button = document.getElementById('login');
button.addEventListener('click',function(){
    var email = document.getElementById('email').value;
    var password = document.getElementById('password').value;
    firebase
        .auth()
        .signInWithEmailAndPassword(email, password)
        .then((data) => {
            console.log(data);
            alert("logged in");
            getRealtimeUsers();
            
        }).catch((err) => {
            res.send(JSON.stringify(err));
            return err;
        });
    
});
function getRealtimeUsers(){
    const db = firebase.firestore();
    db.collection("users").get().then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    });
}

如果您還需要在服務器端登錄,無論出於何種原因,您都可以使用服務器端登錄來登錄。

警告您的服務器端代碼包含一個重大缺陷。 它應該等待 promise 解決:
 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); const config = { apiKey: "AIzaSyAg2GWsL04akpMNezuuz7ObRoXg-goy9jc", authDomain: "stackshop-40f63.firebaseapp.com", projectId: "stackshop-40f63", storageBucket: "stackshop-40f63.appspot.com", messagingSenderId: "537745304409", appId: "1:537745304409:web:2a8bb1f007a6b67c14fa48" }; const firebase = require("firebase"); firebase.initializeApp(config); // Log user in async function login(req, res) { const user = { email: req.body.email, password: req.body.password, }; await firebase.auth().signInWithEmailAndPassword(user.email, user.password).then((data) => { firebase.auth().currentUser.getIdToken(false).then(function(idToken) { // Send token to your backend via HTTPS //... res.send(idToken); //signInWithCustomToken() }).catch(function(error) { // Handle error }); return data; }).catch((err) => { res.send(JSON.stringify(err)); return err; }); } app.post('/login', login);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM