如何解决如何从 Google Identity Aware Proxy 背后的网络应用程序访问已通过身份验证的用户?
我有一个网络应用程序,它位于 Google 的 Identity Aware Proxy (IAP) 后面。 IAP 在转发到我的 Web 应用程序之前对用户进行身份验证。如何从我的网络应用程序访问已通过身份验证的用户?
在 Getting the user's identity 中,它声明有 X-Goog-Authenticated-User-Email
和 X-Goog-Authenticated-User-Id
标头。但是,我在响应标头中没有看到这些:
accept-ranges: bytes
alt-svc: clear
content-length: 14961
content-type: text/html; charset=utf-8
date: Thu,01 Apr 2021 15:21:01 GMT
last-modified: Wed,31 Mar 2021 19:34:58 GMT
via: 1.1 google
我确实看到了一些 cookie:
GCP_IAAP_AUTH_TOKEN_xxx
GCP_IAP_UID
GCP_IAP_XSRF_NONCE_xxx
例如,我希望能够在我的网络应用程序中显示他们的姓名和头像照片,以表明他们已通过身份验证并已登录。我知道该信息可通过 Google 的 OAuth2 结构获得,但我如何从应用内购?
解决方法
在@JohnHanley 提到只有在 IAP 后面运行时才会显示标题后,我才能够使这个工作正常进行。您在本地开发过程中看不到它们。
在部署一个简单的临时 /headers
路由后,我可以看到它们,该路由循环遍历它们并写入 ResponseWriter。 X-Goog-Authenticated-User-Id
、X-Goog-Authenticated-User-Email
和 X-Goog-Iap-Jwt-Assertion
。
import (
"fmt"
"net/http"
"github.com/rs/zerolog/log"
)
func headersHandler(w http.ResponseWriter,r *http.Request) {
log.Info().Msg("Entering headersHandler")
fmt.Fprintf(w,"Request Headers\n\n")
log.Debug().Msg("Request Headers:")
for name,values := range r.Header {
log.Debug().Interface(name,values).Send()
fmt.Fprintf(w,"%s = %s\n",name,values)
}
}
这是一条临时路线。确认标题后,我将其删除。
此外,我必须为托管我的 Web 应用程序的 ProjectId 启用 Google 的 People API。
之后,我使用 google.golang.org/api/people/v1
的 Go 包进行了测试,发现通过 people/me
使用当前经过身份验证的用户的约定在我的情况下不起作用,因为它返回的服务帐户为用过的。相反,我必须以编程方式填写用户 ID people/userid
。然后它起作用了。
对于我的用例,我创建了一个 /user
路由来返回用户信息的子集,即姓名、电子邮件、照片网址。
结构:
type GoogleUser struct {
Name string `json:"name"`
Email string `json:"email"`
PhotoUrl string `json:"photo_url"`
}
处理程序:
func userHandler(w http.ResponseWriter,r *http.Request) {
log.Info().Msg("Entering userHandler")
var err error
// Make sure this is a valid API request
// Request header Content-Type: application/json must be present
if !ValidAPIRequest(r) {
err = writeJSONError(w,ResponseStatusNotFound("Not found"))
if err != nil {
log.Error().Msg(err.Error())
}
return
}
// Extract user id from header
var userId string = r.Header.Get("X-Goog-Authenticated-User-Id")
if userId != "" {
userId = strings.ReplaceAll(userId,"accounts.google.com:","")
}
// Extract user email from header
var userEmail string = r.Header.Get("X-Goog-Authenticated-User-Email")
if userEmail != "" {
userEmail = strings.ReplaceAll(userEmail,"")
}
// Get the currently authenticated Google user
googleUser,err := GetCurrentGoogleUser(userId,userEmail)
if err != nil {
log.Error().Msg(err.Error())
err = writeJSONError(w,ResponseStatusInternalError(err.Error()))
if err != nil {
log.Error().Msg(err.Error())
}
return
}
// Write the JSON response
err = writeJSONGoogleUser(w,http.StatusOK,&googleUser)
if err != nil {
log.Error().Msg(err.Error())
}
}
Google People API:
func GetCurrentGoogleUser(userId string,userEmail string) (GoogleUser,error) {
// Pre-conditions
if userId == "" {
return GoogleUser{},errors.New("userId is blank")
}
if userEmail == "" {
return GoogleUser{},errors.New("userEmail is blank")
}
log.Debug().
Str("userId",userId).
Str("userEmail",userEmail).
Send()
ctx := context.Background()
// Instantiate a new People service
peopleService,err := people.NewService(ctx,option.WithAPIKey(GoogleAPIKey))
if err != nil {
return GoogleUser{},err
}
// Define the resource name using the user id
var resourceName string = fmt.Sprintf("people/%s",userId)
// Get the user profile
profile,err := peopleService.People.Get(resourceName).PersonFields("names,photos").Do()
if err != nil {
return GoogleUser{},err
}
log.Debug().
Interface("profile",profile).
Send()
return GoogleUser{Name: profile.Names[0].DisplayName,Email: userEmail,PhotoUrl: profile.Photos[0].Url},nil
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。