使用新的firebase云功能,我决定将一些HTTP端点移动到firebase。 一切都很好……但我有以下问题。我有两个端点构建HTTP触发器(云函数)

用于创建用户并返回自定义令牌的API端点 由Firebase Admin SDK生成。 获取特定用户详细信息的API端点。

虽然第一个端点很好,但对于第二个端点,我希望仅为经过身份验证的用户保护它。意思是拥有我之前生成的令牌的人。

我该怎么解呢?

我知道我们可以在云函数中使用Header参数

request.get('x-myheader')

但是有没有一种方法可以像保护实时数据库一样保护端点呢?


当前回答

在Firebase中,为了简化你的代码和工作,这只是一个架构设计的问题:

For public accessible sites/contents, use HTTPS triggers with Express. To restrict only samesite or specific site only, use CORS to control this aspect of security. This make sense because Express is useful for SEO due to its server-side rendering content. For apps that require user authentication, use HTTPS Callable Firebase Functions, then use the context parameter to save all the hassles. This also makes sense, because such as a Single Page App built with AngularJS -- AngularJS is bad for SEO, but since it's a password protected app, you don't need much of the SEO either. As for templating, AngularJS has built-in templating, so no need for sever-side template with Express. Then Firebase Callable Functions should be good enough.

有了以上的思想,没有更多的麻烦,让生活更容易。

其他回答

对于您正在尝试做的事情,有一个正式的代码示例。它演示了如何设置HTTPS函数,以要求使用客户端在身份验证期间接收到的令牌作为授权标头。该函数使用firebase-admin库来验证令牌。

此外,如果你的应用程序能够使用Firebase客户端库,你可以使用“可调用函数”来简化这个样板文件。

正如@Doug所提到的,您可以使用firebase-admin来验证令牌。我举了一个简单的例子:

exports.auth = functions.https.onRequest((req, res) => {
  cors(req, res, () => {
    const tokenId = req.get('Authorization').split('Bearer ')[1];
    
    return admin.auth().verifyIdToken(tokenId)
      .then((decoded) => res.status(200).send(decoded))
      .catch((err) => res.status(401).send(err));
  });
});

在上面的例子中,我也启用了CORS,但这是可选的。首先,获取Authorization头并找出令牌。

然后,您可以使用firebase-admin来验证该令牌。您将在响应中获得该用户的解码信息。否则,如果令牌无效,它将抛出一个错误。

这里有很多很棒的信息真的对我很有帮助,但是我认为,对于那些第一次使用Angular尝试使用它的人来说,分解一个简单的工作示例可能会很好。谷歌Firebase文档可以在https://firebase.google.com/docs/auth/admin/verify-id-tokens#web上找到。

//#### YOUR TS COMPONENT FILE #####
import { Component, OnInit} from '@angular/core';
import * as firebase from 'firebase/app';
import { YourService } from '../services/yourservice.service';

@Component({
  selector: 'app-example',
  templateUrl: './app-example.html',
  styleUrls: ['./app-example.scss']
})

export class AuthTokenExample implements OnInit {

//property
idToken: string;

//Add your service
constructor(private service: YourService) {}

ngOnInit() {

    //get the user token from firebase auth
    firebase.auth().currentUser.getIdToken(true).then((idTokenData) => {
        //assign the token to the property
        this.idToken = idTokenData;
        //call your http service upon ASYNC return of the token
        this.service.myHttpPost(data, this.idToken).subscribe(returningdata => {
            console.log(returningdata)
        });

    }).catch((error) => {
        // Handle error
        console.log(error);
    });

  }

}

//#### YOUR SERVICE #####
//import of http service
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class MyServiceClass {

    constructor(private http: HttpClient) { }

  //your myHttpPost method your calling from your ts file
  myHttpPost(data: object, token: string): Observable<any> {

    //defining your header - token is added to Authorization Bearer key with space between Bearer, so it can be split in your Google Cloud Function
    let httpOptions = {
        headers: new HttpHeaders({
            'Content-Type': 'application/json',
         'Authorization': 'Bearer ' + token
        })
    }

    //define your Google Cloud Function end point your get from creating your GCF
    const endPoint = ' https://us-central1-your-app.cloudfunctions.net/doSomethingCool';

    return this.http.post<string>(endPoint, data, httpOptions);

  }

}


//#### YOUR GOOGLE CLOUD FUNCTION 'GCF' #####
//your imports
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({origin: true});


exports.doSomethingCool = functions.https.onRequest((req, res) => {

//cross origin middleware
    cors(req, res, () => {

        //get the token from the service header by splitting the Bearer in the Authorization header 
        const tokenId = req.get('Authorization').split('Bearer ')[1];

        //verify the authenticity of token of the user
        admin.auth().verifyIdToken(tokenId)
            .then((decodedToken) => {
                //get the user uid if you need it.
               const uid = decodedToken.uid;

                //do your cool stuff that requires authentication of the user here.

            //end of authorization
            })
            .catch((error) => {
                console.log(error);
            });

    //end of cors
    })

//end of function
})

我一直在努力在golang GCP函数中获得正确的firebase身份验证。实际上没有这样的例子,所以我决定构建这个小库:https://github.com/Jblew/go-firebase-auth-in-gcp-functions

现在,您可以使用firebase-auth(它与gcp-authenticated-functions不同,并且身份识别代理不直接支持)轻松地对用户进行身份验证。

下面是一个使用实用程序的示例:

import (
  firebaseGcpAuth "github.com/Jblew/go-firebase-auth-in-gcp-functions"
  auth "firebase.google.com/go/auth"
)

func SomeGCPHttpCloudFunction(w http.ResponseWriter, req *http.Request) error {
   // You need to provide 1. Context, 2. request, 3. firebase auth client
  var client *auth.Client
    firebaseUser, err := firebaseGcpAuth.AuthenticateFirebaseUser(context.Background(), req, authClient)
    if err != nil {
    return err // Error if not authenticated or bearer token invalid
  }

  // Returned value: *auth.UserRecord
}

请记住,部署函数时使用——allow-unauthenticated标志(因为firebase身份验证是在函数执行过程中进行的)。

希望这能帮助你,就像它帮助了我一样。出于性能方面的考虑,我决定使用golang来实现云函数——jlddrzej

在Firebase中,为了简化你的代码和工作,这只是一个架构设计的问题:

For public accessible sites/contents, use HTTPS triggers with Express. To restrict only samesite or specific site only, use CORS to control this aspect of security. This make sense because Express is useful for SEO due to its server-side rendering content. For apps that require user authentication, use HTTPS Callable Firebase Functions, then use the context parameter to save all the hassles. This also makes sense, because such as a Single Page App built with AngularJS -- AngularJS is bad for SEO, but since it's a password protected app, you don't need much of the SEO either. As for templating, AngularJS has built-in templating, so no need for sever-side template with Express. Then Firebase Callable Functions should be good enough.

有了以上的思想,没有更多的麻烦,让生活更容易。