使用 apollo graphql 对 firebase 身份验证做出反应

Posted

技术标签:

【中文标题】使用 apollo graphql 对 firebase 身份验证做出反应【英文标题】:react firebase authentication with apollo graphql 【发布时间】:2018-12-03 09:47:58 【问题描述】:

我发现了一篇很棒的文章,将身份验证添加到 react 中。 文章:https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/

本文使用一个 HOC 组件完成了 firebase 设置(在 redux 之前),我可以将其放入应用程序并可以通过上下文访问。

我的问题是如何将它放入应用程序组件之外的 apollo 客户端,因此即使在上下文中我也无法设置它。我对 redux 也有同样的问题。我发现只有一个是使用本地存储,但我想避免这种情况。

这是我在主应用组件中的 apollo 客户端。

const client = new ApolloClient(   
    uri: clientUrl,
  request: async operation => 
        const token = How_do_i_set_this <-- ???
        console.log('token in request', token)
    operation.setContext(
      headers: 
        authorization: token ? `Bearer $token` : ''
      
    );
    
);

const App = () => (
    <DashAppHolder>
        <ApolloProvider client=client>
            <Provider store=store>
                <PublicRoutes history=history />
            </Provider>
        </ApolloProvider>
    </DashAppHolder>
);

【问题讨论】:

以上这些你都做对了吗? @Phobos 我刚刚发布了一个关于我如何设置和工作的答案 【参考方案1】:

所以这不是最好的方法,但这就是我目前的设置方式。

这是我的 apollo 客户端设置

import Firebase from './helpers/firebase';
import ApolloClient from "apollo-boost";

const client = new ApolloClient(   
    uri: clientUrl,
  request: async operation => 
    const fireToken = await Firebase.token();
    console.log('fire token', fireToken);
    operation.setContext(
      headers: 
        authorization: fireToken ? `Bearer $fireToken` : 'token bad'
      
    );
    
);

这是我导入的 firebase 助手类

import firebase from 'firebase';
import 'firebase/firestore';
import  firebaseConfig  from '../../settings';

const valid = firebaseConfig && firebaseConfig.apiKey && firebaseConfig.projectId;

const firebaseApp = firebase.initializeApp(firebaseConfig);
const firebaseAuth = firebase.auth;

class FirebaseHelper 
    isValid = valid;
    EMAIL = 'email';
    FACEBOOK = 'facebook';
    GOOGLE = 'google';
    GITHUB = 'github';
    TWITTER = 'twitter';
    constructor() 
        this.login = this.login.bind(this);
        this.logout = this.logout.bind(this);
        this.signup = this.signup.bind(this);
        this.resetPassword = this.resetPassword.bind(this);
        this.doPasswordUpdate = this.doPasswordUpdate.bind(this);
        this.auth = this.auth.bind(this);
        this.database = firebase.firestore();
    
    token = async() => 
        const user = this.user()
        if (user) 
            return await user.getIdToken().then(token =>  return token );
         else 
            return null;
        
    

    user() 
        return firebaseAuth().currentUser;
    

    login(provider, info) 
        switch (provider) 
            case this.EMAIL:
                return firebaseAuth().signInWithEmailAndPassword(
                    info.email,
                    info.password
                );
            case this.GOOGLE:
                var googleProvider = new firebase.auth.GoogleAuthProvider();
                return firebaseAuth().signInWithPopup(googleProvider);
            default:
        
    

    signup(provider, info) 
        switch (provider) 
            case this.EMAIL:
                return firebaseAuth().createUserWithEmailAndPassword(
                    info.email,
                    info.password
                );
            case this.FACEBOOK:
                return firebaseAuth().FacebookAuthProvider();
            case this.GOOGLE:
                return firebaseAuth().GoogleAuthProvider();
            case this.GITHUB:
                return firebaseAuth().GithubAuthProvider();
            case this.TWITTER:
                return firebaseAuth().TwitterAuthProvider();
            default:
                alert('defaulted');
        
    

    logout() 
        return firebaseAuth().signOut();
    

    auth = () => 
        return firebaseAuth()
    
    resetPassword(email) 
        return firebaseAuth().sendPasswordResetEmail(email);
    

    doPasswordUpdate(password) 
        firebaseAuth().currentUser.updatePassword(password);
    

    createNewRef() 
        return firebase
            .database()
            .ref()
            .push().key;
    

最后在服务器上是我使用的graphql设置相关信息

const admin = require('firebase-admin');

const getUid = async (request) => 
    let idToken = (request.headers && request.headers.authorization) ? request.headers.authorization : null;
    if (!idToken) 
        console.log('no token found');
        return null;
   
    console.log('raw token', idToken);
    var newToken = idToken.replace("Bearer ", "");
    console.log('pure token', newToken)
    let uid = await admin.auth().verifyIdToken(newToken)
        .then(decodedToken => 
            var uid = decodedToken.uid;
            return uid;
        ).catch((error) => 
            // Handle error
            console.log('uid failed', error);
            return null;
        );
    console.log('uid found', uid);
    return uid;


app.use(
    '/graphql',
    cors(),
    express.json(),
    graphqlExpress(async (request) => (
        schema: schema,
        context: 
            request: request,
            uid: await getUid(request),
            accountLoader: new Dataloader(keys => batchAccounts(keys, db)),
            dealLoader: new Dataloader(keys => batchDeals(keys, db)),
        
    )),
);

这个答案有效,让我获得了通过 firebase 授权的用户的 UID,看起来完全没有延迟。这可能不是最好的答案,因为当我刚刚学习所有内容时,我将几个文档放在一起,并且一直打算在我有时间但再次工作时返回并重新访问。

【讨论】:

以上是关于使用 apollo graphql 对 firebase 身份验证做出反应的主要内容,如果未能解决你的问题,请参考以下文章

对 graphql 查询使用 try catch 块

不能对 Type-GraphQL 字段类型使用类型“对象”

如何使用 apollo 服务器对 graphQl 中的数据进行排序?

使用模式对 GraphQL 响应进行类型保留反序列化

使用 Mock Service Worker 时如何对 graphql 查询变量进行断言?

如何解析和编组 GraphQL 对 Java POJO 的响应?