새로운 firebase 클라우드 기능을 사용하여 일부 HTTP 엔드 포인트를 firebase로 옮기기로 결정했습니다. 모든 것이 잘 작동합니다 …하지만 다음과 같은 문제가 있습니다. HTTP 트리거 (클라우드 함수)로 두 개의 엔드 포인트 빌드가 있습니다.
- 사용자를 생성하고 Firebase Admin SDK에서 생성 한 맞춤 토큰을 반환하는 API 엔드 포인트입니다.
- 특정 사용자 세부 사항을 가져 오는 API 엔드 포인트입니다.
첫 번째 끝점은 괜찮지 만 두 번째 끝점은 인증 된 사용자 만 보호하려고합니다. 내가 이전에 생성 한 토큰을 가진 사람을 의미합니다.
이 문제를 해결하려면 어떻게해야합니까?
클라우드 함수에서 헤더 매개 변수를 사용할 수 있다는 것을 알고 있습니다.
request.get('x-myheader')
그러나 실시간 데이터베이스를 보호하는 것처럼 엔드 포인트를 보호 할 수있는 방법이 있습니까?
답변
수행하려는 작업에 대한 공식 코드 샘플 이 있습니다. 인증하는 동안 클라이언트가 수신 한 토큰이있는 Authorization 헤더를 요구하도록 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
헤더 를 가져 와서 를 찾으십시오 token
.
그런 다음 firebase-admin
해당 토큰을 확인하는 데 사용할 수 있습니다 . 응답에서 해당 사용자에 대한 디코딩 된 정보를 얻을 수 있습니다. 그렇지 않으면 토큰이 유효하지 않으면 오류가 발생합니다.
답변
@Doug에서 언급했듯이 Callable Functions 를 사용 하여 클라이언트와 서버에서 상용구 코드 를 제외 할 수 있습니다 .
호출 가능 함수 예 :
export const getData = functions.https.onCall((data, context) => {
// verify Firebase Auth ID token
if (!context.auth) {
return { message: 'Authentication Required!', code: 401 };
}
// do your things..
const uid = context.auth.uid;
const query = data.query;
return { message: 'Some Data', code: 400 };
});
다음과 같이 클라이언트에서 직접 호출 할 수 있습니다.
firebase.functions().httpsCallable('getData')({query}).then(result => console.log(result));
답변
위의 메소드 는 함수 내부 의 논리를 사용하여 사용자를 인증 하므로 검사를 수행하려면 함수를 계속 호출해야합니다.
그것은 완전히 훌륭한 방법이지만 이해를 위해 대안이 있습니다.
등록 된 사용자 (권한을 결정) 가 아닌 한 호출 할 수 없도록 기능을 “비공개”로 설정할 수 있습니다 . 이 경우 인증되지 않은 요청은 함수 컨텍스트 외부에서 거부되며 함수가 전혀 호출 되지 않습니다 .
다음은 (a) 기능을 퍼블릭 / 프라이빗 으로 구성한 다음 (b) 기능에 대한 최종 사용자 인증에 대한 참조 입니다.
모든 중포 기지 프로젝트이기 때문에 문서가 위의이 작품은, 실제로 Google 클라우드 플랫폼 용이며, 참고 도 GCP 프로젝트. 이 방법과 관련하여주의해야 할 점은 서면으로 Google 계정 기반 인증에서만 작동한다는 것입니다.
답변
Express를 사용하는 멋진 공식 예가 있습니다. https://github.com/firebase/functions-samples/blob/master/authorized-https-endpoint/functions/index.js (아래에 붙여 넣기) 확실히)
슬러그에서 exports.app
함수를 사용할 수 있음 을 명심하십시오 /app
(이 경우 하나의 함수 만 있고 아래에서 사용할 수 있습니다 <you-firebase-app>/app/hello
.) 제거하려면 실제로 Express 부분을 약간 다시 작성해야합니다 (유효성 검사를위한 미들웨어 부분은 동일하게 유지됩니다-매우 효과적입니다) 좋았고 의견 덕분에 이해할 수 있습니다).
/**
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const express = require('express');
const cookieParser = require('cookie-parser')();
const cors = require('cors')({origin: true});
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = async (req, res, next) => {
console.log('Check if request is authorized with Firebase ID token');
if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
!(req.cookies && req.cookies.__session)) {
console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
'Make sure you authorize your request by providing the following HTTP header:',
'Authorization: Bearer <Firebase ID Token>',
'or by passing a "__session" cookie.');
res.status(403).send('Unauthorized');
return;
}
let idToken;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
console.log('Found "Authorization" header');
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1];
} else if(req.cookies) {
console.log('Found "__session" cookie');
// Read the ID Token from cookie.
idToken = req.cookies.__session;
} else {
// No cookie
res.status(403).send('Unauthorized');
return;
}
try {
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
next();
return;
} catch (error) {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
return;
}
};
app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/hello', (req, res) => {
res.send(`Hello ${req.user.name}`);
});
// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.app = functions.https.onRequest(app);
제거하기 위해 다시 작성 /app
:
const hello = functions.https.onRequest((request, response) => {
res.send(`Hello ${req.user.name}`);
})
module.exports = {
hello
}
답변
golang GCP 기능에서 적절한 firebase 인증을 받기 위해 고심하고 있습니다. 실제로 이에 대한 예는 없으므로이 작은 라이브러리를 빌드하기로 결정했습니다. https://github.com/Jblew/go-firebase-auth-in-gcp-functions
이제 firebase-auth를 사용하여 사용자를 쉽게 인증 할 수 있습니다 (gcp 인증 기능과 다르며 ID 인식 프록시가 직접 지원하지 않음).
다음은이 유틸리티를 사용하는 예입니다.
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을 사용하기로 결정했습니다. — Jędrzej
답변
Firebase에서는 코드와 작업을 단순화하기 위해 건축 설계 의 문제입니다 .
- 공개적으로 액세스 가능한 사이트 / 콘텐츠의 경우 와 함께 HTTPS 트리거를 사용하십시오
Express
. 동일한 사이트 또는 특정 사이트 만 제한하려면을 사용CORS
하여이 보안 측면을 제어하십시오. 이는Express
서버 측 렌더링 컨텐츠로 인해 SEO에 유용하기 때문에 의미 가 있습니다. - 사용자 인증이 필요한 앱의 경우 HTTPS Callable Firebase Functions 를 사용한 다음
context
매개 변수를 사용하여 모든 번거 로움을 저장하십시오. AngularJS로 빌드 된 단일 페이지 앱과 같이 AngularJS는 SEO에는 좋지 않지만 암호로 보호되는 앱이므로 SEO도 많이 필요하지 않습니다. 템플릿과 관련하여 AngularJS에는 템플릿이 내장되어 있으므로을 사용하여 서버 측 템플릿이 필요하지 않습니다Express
. 그러면 Firebase Callable Functions가 충분해야합니다.
위의 사항을 염두에두고 더 이상 번거 로움을 없애고 인생을 더 편하게 만듭니다.