GCP API 게이트웨이: Firebase 인증
23615 단어 firebasegogooglecloud
Google Cloud Platform API 게이트웨이
github 저장소 --> here
API 게이트웨이란 무엇입니까?
documentation에 따라 Api 게이트웨이는 서버리스 워크로드를 위한 완전 관리형 게이트웨이입니다.
그래서 정말 하루가 끝나면 서버리스 API를 위한 서버리스 게이트웨이로 귀결됩니다. 서버리스가 너무 많습니다.
API 게이트웨이는 무엇을 합니까?
API 게이트웨이는 최종 사용자와 서비스 사이의 중개자 역할을 합니다. OpenAPI 사양에 따라 서비스를 설명합니다.
사양을 API 게이트웨이 센터에 업로드한 다음 마지막으로 사양을 게이트웨이에 배포합니다. API Gateway는 모니터링, 로깅 및 인증과 같은 유틸리티 제품군도 제공합니다.
API 게이트웨이는 언제 사용해야 합니까?
서버리스 GCP 에코시스템(Cloud Functions, Cloud Run, App Engine)을 사용하려는 경우 API 게이트웨이는 이러한 서버리스 제품에 무료입니다.
API 게이트웨이를 사용해야 하는 이유는 무엇입니까?
대답해야 할 가장 중요한 질문은 "왜"입니다. 왜 API Gateway를 사용해야 합니까?
보안 - 핵심 애플리케이션은 GCP IAM에 의해 배포 및 보호될 수 있습니다. 이렇게 하면 서비스와의 직접적인 상호 작용만 api 게이트웨이를 통해 수행됩니다.
외부화된 구성 - 애플리케이션 컨텍스트 외부에 있는 애플리케이션 인증, 서비스 URL 매핑 및 API 문서를 관리하는 외부 방법이 있습니다.
적은 코드 - JWT/Api 키 유효성 검사에 대해 애플리케이션 자체에서 걱정할 필요가 없습니다. JWT/Api 키가 게이트웨이 계층에서 처리되고 결과가 애플리케이션으로 전달되기 때문입니다. 작성하는 코드가 적을수록 버그가 줄어듭니다 😬
관찰 가능성 - 모든 성능 메트릭은 요청 대기 시간, 오류율, 초당 요청 수 등과 같은 모든 KPI가 포함된 보기 쉬운 단일 대시보드로 롤업됩니다.
Firebase 인증으로 Cloud Run 서비스를 보호합니다.
먼저 API를 이해하기 위해 openapi 사양 파일을 살펴보겠습니다. 사용자 이름을 "인사하는"형식으로 되풀이하는 단일 끝점/greet
으로 매우 간단합니다.
openapi2-run.yaml
swagger: '2.0'
info:
# Title of the api gateway
title: gateway
description: Sample API on API Gateway with a Cloud Run backend
version: 1.0.0
schemes:
- https
produces:
- application/json
# The cloud run service url, this could also be defined per path as well in case you have multiple cloud run services that
# make up a single gateway
x-google-backend:
address: "YOUR-CLOUD_RUN-URL"
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# Replace YOUR-PROJECT-ID with your project ID
x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]"
x-google-audiences: "YOUR-PROJECT-ID"
paths:
/greet:
get:
summary: Greets the user
operationId: greet
# define that our service uses the firebase security definition
security:
- firebase: [ ]
responses:
'200':
description: A successful response
schema:
type: object
# our object look like `{name: ""}`
properties:
name:
type: string
description: The users name
이제 api의 계약을 이행할 코드를 살펴보겠습니다.
cmd/routes.go
func (s *server) routes() {
s.router.HandleFunc("/greet", s.handleAuth(s.handleGreeting()))
}
//handleGreeting will fetch the UserInfo struct that is stored in context from our auth middleware and use that to greet the person that called our api
func (s *server) handleGreeting() http.HandlerFunc {
type person struct {
Name string `json:"name"`
}
return func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
// fetch the token user object that is stored in context
userObj := request.Context().Value(gatewayUserContext).(UserInfo)
// greet the user 👋
p := person{Name: fmt.Sprintf("Hello 👋 %s", userObj.Name)}
decoder := json.NewEncoder(writer)
if err := decoder.Encode(p); err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
}
}
}
그리고 Auth 미들웨어에 대한 빠른 검토를 위해.
cmd/auth.go
const gatewayUserInfoHeader = "X-Apigateway-Api-Userinfo"
const gatewayUserContext = "GATEWAY_USER"
type UserInfo struct {
Name string `json:"name"`
Picture string `json:"picture"`
Iss string `json:"iss"`
Aud string `json:"aud"`
AuthTime int `json:"auth_time"`
UserID string `json:"user_id"`
Sub string `json:"sub"`
Iat int `json:"iat"`
Exp int `json:"exp"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
Firebase Firebase `json:"firebase"`
}
type Identities struct {
GoogleCom []string `json:"google.com"`
Email []string `json:"email"`
}
type Firebase struct {
Identities Identities `json:"identities"`
SignInProvider string `json:"sign_in_provider"`
}
// handleAuth is a piece of middleware that will parse the gatewayUserInfoHeader from the request and add the UserInfo to the request context
func (s *server) handleAuth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
encodedUser := r.Header.Get(gatewayUserInfoHeader)
if encodedUser == "" {
http.Error(w, "User Not Available", http.StatusForbidden)
return
}
decodedBytes, err := base64.RawURLEncoding.DecodeString(encodedUser)
if err != nil {
http.Error(w, "Invalid UserInfo", http.StatusForbidden)
return
}
decoder := json.NewDecoder(bytes.NewReader(decodedBytes))
var userToken UserInfo
err = decoder.Decode(&userToken)
if err != nil {
http.Error(w, "Invalid UserInfo", http.StatusForbidden)
return
}
ctx := context.WithValue(r.Context(), gatewayUserContext, userToken)
h.ServeHTTP(w, r.WithContext(ctx))
}
}
github repo에서 애플리케이션에 대한 나머지 코드를 볼 수 있습니다.
API 활성화 및 서비스 계정 생성
프로젝트에서 다음 API를 활성화했는지 확인하십시오.
gcloud services enable apigateway.googleapis.com
gcloud services enable servicemanagement.googleapis.com
gcloud services enable servicecontrol.googleapis.com
API 게이트웨이 서비스 계정을 만들 수 있습니다.
gcloud iam service-accounts create api-gateway
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID --member "serviceAccount:api-gateway@YOUR_PROJECT_ID.iam.gserviceaccount.com" --role "roles/run.invoker"
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID --member "serviceAccount:api-gateway@YOUR_PROJECT_ID.iam.gserviceaccount.com" --role "roles/iam.serviceAccountUser"
빌드 및 배포
클라우드 빌드를 사용하여 모든 것을 출시할 예정이므로 컨테이너를 빌드하고 배포하도록 합시다. gcloud builds submit
cloudbuild.yaml
steps:
# Run the docker build
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/greeter', '.' ]
# push the docker image to the private GCR registry
- name: 'gcr.io/cloud-builders/docker'
args: [ 'push', 'gcr.io/$PROJECT_ID/greeter' ]
# deploy to cloud run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args: [ 'run', 'deploy', 'greeter', '--image', 'gcr.io/$PROJECT_ID/greeter', '--region', 'us-central1', '--platform', 'managed', '--no-allow-unauthenticated' ]
images:
- 'gcr.io/$PROJECT_ID/greeter'
이제 클라우드 서비스가 배포되었으므로 클라우드 실행 URLgcloud run services describe greeter --format 'value(status.url)'
만 가져오면 됩니다.
보안을 확인하기 위해 엔드포인트curl
를 curl $(gcloud run services describe greeter --format 'value(status.url)')
시도할 수 있으며 403을 얻어야 합니다.
다음 단계는 엔드포인트에서 해당 URL을 가져와 x-google-backend
의 주소로 API 사양에 연결하는 것입니다.
# The cloud run service url, this could also be defined per path as well in case you have multiple cloud run services that
# make up a single gateway
x-google-backend:
address: "YOUR-CLOUD_RUN-URL"
이제 우리는 홈 스트레치로 전환하고 있습니다. 게이트웨이/구성을 배포하기만 하면 됩니다.
# create api config
gcloud beta api-gateway api-configs create echoconf \
--api=gateway --openapi-spec=openapi2-run.yaml \
--backend-auth-service-account=api-gateway@YOUR_PROJECT_ID.iam.gserviceaccount.com
# create gateway with config
gcloud beta api-gateway gateways create gateway \
--api=gateway --api-config=echoconf \
--location=us-central1
#get hostname from gateway
gcloud beta api-gateway gateways describe gateway \
--location=us-central1 --format 'value(defaultHostname)'
이제 게이트웨이 끝점을 curl
다음과 같이 하면
curl "https://$(gcloud beta api-gateway gateways describe gateway --location=us-central1 --format 'value(defaultHostname)')/greet"
요청에 Firebase ID 토큰을 첨부하지 않았기 때문에 401이 표시됩니다.
그러나 요청에 토큰을 access_token
의 쿼리 매개변수 또는 전달자 토큰이 있는 Authorization 헤더로 첨부하면
curl "https://$(gcloud beta api-gateway gateways describe gateway --location=us-central1 --format 'value(defaultHostname)')/greet?access_token=ACCESS_TOKEN"
우리는 우리의 인사 메시지를 돌려받을 것입니다! {
"name": "Hello 👋 Alex Mammay"
}
Reference
이 문제에 관하여(GCP API 게이트웨이: Firebase 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/amammay/gcp-api-gateway-firebase-authentication-34j7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
swagger: '2.0'
info:
# Title of the api gateway
title: gateway
description: Sample API on API Gateway with a Cloud Run backend
version: 1.0.0
schemes:
- https
produces:
- application/json
# The cloud run service url, this could also be defined per path as well in case you have multiple cloud run services that
# make up a single gateway
x-google-backend:
address: "YOUR-CLOUD_RUN-URL"
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# Replace YOUR-PROJECT-ID with your project ID
x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]"
x-google-audiences: "YOUR-PROJECT-ID"
paths:
/greet:
get:
summary: Greets the user
operationId: greet
# define that our service uses the firebase security definition
security:
- firebase: [ ]
responses:
'200':
description: A successful response
schema:
type: object
# our object look like `{name: ""}`
properties:
name:
type: string
description: The users name
func (s *server) routes() {
s.router.HandleFunc("/greet", s.handleAuth(s.handleGreeting()))
}
//handleGreeting will fetch the UserInfo struct that is stored in context from our auth middleware and use that to greet the person that called our api
func (s *server) handleGreeting() http.HandlerFunc {
type person struct {
Name string `json:"name"`
}
return func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
// fetch the token user object that is stored in context
userObj := request.Context().Value(gatewayUserContext).(UserInfo)
// greet the user 👋
p := person{Name: fmt.Sprintf("Hello 👋 %s", userObj.Name)}
decoder := json.NewEncoder(writer)
if err := decoder.Encode(p); err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
}
}
}
const gatewayUserInfoHeader = "X-Apigateway-Api-Userinfo"
const gatewayUserContext = "GATEWAY_USER"
type UserInfo struct {
Name string `json:"name"`
Picture string `json:"picture"`
Iss string `json:"iss"`
Aud string `json:"aud"`
AuthTime int `json:"auth_time"`
UserID string `json:"user_id"`
Sub string `json:"sub"`
Iat int `json:"iat"`
Exp int `json:"exp"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
Firebase Firebase `json:"firebase"`
}
type Identities struct {
GoogleCom []string `json:"google.com"`
Email []string `json:"email"`
}
type Firebase struct {
Identities Identities `json:"identities"`
SignInProvider string `json:"sign_in_provider"`
}
// handleAuth is a piece of middleware that will parse the gatewayUserInfoHeader from the request and add the UserInfo to the request context
func (s *server) handleAuth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
encodedUser := r.Header.Get(gatewayUserInfoHeader)
if encodedUser == "" {
http.Error(w, "User Not Available", http.StatusForbidden)
return
}
decodedBytes, err := base64.RawURLEncoding.DecodeString(encodedUser)
if err != nil {
http.Error(w, "Invalid UserInfo", http.StatusForbidden)
return
}
decoder := json.NewDecoder(bytes.NewReader(decodedBytes))
var userToken UserInfo
err = decoder.Decode(&userToken)
if err != nil {
http.Error(w, "Invalid UserInfo", http.StatusForbidden)
return
}
ctx := context.WithValue(r.Context(), gatewayUserContext, userToken)
h.ServeHTTP(w, r.WithContext(ctx))
}
}
gcloud services enable apigateway.googleapis.com
gcloud services enable servicemanagement.googleapis.com
gcloud services enable servicecontrol.googleapis.com
gcloud iam service-accounts create api-gateway
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID --member "serviceAccount:api-gateway@YOUR_PROJECT_ID.iam.gserviceaccount.com" --role "roles/run.invoker"
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID --member "serviceAccount:api-gateway@YOUR_PROJECT_ID.iam.gserviceaccount.com" --role "roles/iam.serviceAccountUser"
steps:
# Run the docker build
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/greeter', '.' ]
# push the docker image to the private GCR registry
- name: 'gcr.io/cloud-builders/docker'
args: [ 'push', 'gcr.io/$PROJECT_ID/greeter' ]
# deploy to cloud run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args: [ 'run', 'deploy', 'greeter', '--image', 'gcr.io/$PROJECT_ID/greeter', '--region', 'us-central1', '--platform', 'managed', '--no-allow-unauthenticated' ]
images:
- 'gcr.io/$PROJECT_ID/greeter'
# The cloud run service url, this could also be defined per path as well in case you have multiple cloud run services that
# make up a single gateway
x-google-backend:
address: "YOUR-CLOUD_RUN-URL"
# create api config
gcloud beta api-gateway api-configs create echoconf \
--api=gateway --openapi-spec=openapi2-run.yaml \
--backend-auth-service-account=api-gateway@YOUR_PROJECT_ID.iam.gserviceaccount.com
# create gateway with config
gcloud beta api-gateway gateways create gateway \
--api=gateway --api-config=echoconf \
--location=us-central1
#get hostname from gateway
gcloud beta api-gateway gateways describe gateway \
--location=us-central1 --format 'value(defaultHostname)'
curl "https://$(gcloud beta api-gateway gateways describe gateway --location=us-central1 --format 'value(defaultHostname)')/greet"
curl "https://$(gcloud beta api-gateway gateways describe gateway --location=us-central1 --format 'value(defaultHostname)')/greet?access_token=ACCESS_TOKEN"
"name": "Hello 👋 Alex Mammay"
}
Reference
이 문제에 관하여(GCP API 게이트웨이: Firebase 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/amammay/gcp-api-gateway-firebase-authentication-34j7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)