如何从Google身份感知代理背后的web应用程序访问已经通过身份验证的用户?

如何从Google身份感知代理背后的web应用程序访问已经通过身份验证的用户?,web,google-cloud-platform,google-iap,identity-aware-proxy,google-cloud-identity-aware-proxy,Web,Google Cloud Platform,Google Iap,Identity Aware Proxy,Google Cloud Identity Aware Proxy,我有一个web应用程序,它位于Google的身份识别代理(IAP)后面。IAP在转发到我的web应用程序之前对用户进行身份验证。如何从web应用程序访问已通过身份验证的用户 在它的状态中有X-Goog-Authenticated-User-Email和X-Goog-Authenticated-User-Id标题。但是,我在响应标题中没有看到这些内容: accept-ranges: bytes alt-svc: clear content-length: 14961 content-type: t

我有一个web应用程序,它位于Google的身份识别代理(IAP)后面。IAP在转发到我的web应用程序之前对用户进行身份验证。如何从web应用程序访问已通过身份验证的用户

在它的状态中有
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
我确实看到一些饼干:

GCP_IAAP_AUTH_TOKEN_xxx
GCP_IAP_UID
GCP_IAP_XSRF_NONCE_xxx

例如,我希望能够在我的web应用程序中显示他们的姓名和头像照片,以表明他们已通过身份验证并登录。我知道可以通过谷歌的OAuth2结构获取信息,但我如何从IAP获取这些信息?

在@JohnHanley提到只有在IAP后面运行时才会显示标题后,我才能够实现这一点。在本地开发期间,您无法看到它们

在部署了一个简单的、临时的,
/headers
路由后,我可以看到它们,该路由在它们之间循环并写入ResponseWriter
X-Goog-Authenticated-User-Id
X-Goog-Authenticated-User-Email
X-Goog-Iap-Jwt-Assertion

导入(
“fmt”
“net/http”
“github.com/rs/zerolog/log”
)
func headersHandler(w http.ResponseWriter,r*http.Request){
log.Info().Msg(“输入HeaderHandler”)
fmt.Fprintf(w,“请求头\n\n”)
log.Debug().Msg(“请求头:”)
对于名称,值:=范围r.标题{
log.Debug().Interface(名称、值).Send()
fmt.Fprintf(w,“%s=%s\n”,名称,值)
}
}
这是一条临时路线。一旦我可以确认标题,我就删除了它

此外,我还必须为我的web应用程序所在的Projectd启用Google

之后,我使用google.golang.org/api/people/v1的Go包进行了测试,发现通过
people/me
使用当前已验证用户的约定在我的情况下不起作用,因为它返回正在使用的服务帐户。相反,我必须以编程方式填写用户id
people/userid
。然后它成功了

对于我的用例,我创建了一个
/user
路由来返回用户信息的子集,即姓名、电子邮件、照片url

结构:

type GoogleUser结构{
名称字符串`json:“名称”`
电子邮件字符串`json:“电子邮件”`
PhotoUrl字符串`json:“照片url”`
}
处理程序:

func用户处理程序(w http.ResponseWriter,r*http.Request){
log.Info().Msg(“输入userHandler”)
变量错误
//确保这是一个有效的API请求
//请求头内容类型:必须存在application/json
如果!ValidAPIRequest(r){
err=writeJSONError(w,ResponseStatusNotFound(“未找到”))
如果错误!=零{
log.Error().Msg(err.Error())
}
返回
}
//从标题中提取用户id
var userId string=r.Header.Get(“X-Goog-Authenticated-User-Id”)
如果用户ID!“”{
userId=strings.ReplaceAll(userId,“accounts.google.com:”,“”)
}
//从邮件头中提取用户电子邮件
var userEmail string=r.Header.Get(“X-Goog-Authenticated-User-Email”)
如果用户电子邮件!“”{
userEmail=strings.ReplaceAll(userEmail,“accounts.google.com:”,“”)
}
//获取当前经过身份验证的Google用户
googleUser,err:=GetCurrentGoogleUser(用户ID,用户电子邮件)
如果错误!=零{
log.Error().Msg(err.Error())
err=writeJSONError(w,ResponseStatusInternalError(err.Error()))
如果错误!=零{
log.Error().Msg(err.Error())
}
返回
}
//编写JSON响应
err=writeJSONGoogleUser(w、http.StatusOK和googleUser)
如果错误!=零{
log.Error().Msg(err.Error())
}
}
Google People API:

func GetCurrentGoogleUser(用户ID字符串,用户电子邮件字符串)(GoogleUser,错误){
//先决条件
如果userId==“”{
返回GoogleUser{},errors.New(“userId为空”)
}
如果userEmail==“”{
返回GoogleUser{},errors.New(“userEmail为空”)
}
log.Debug()。
Str(“userId”,userId)。
Str(“userEmail”,userEmail)。
发送()
ctx:=context.Background()
//实例化一个新的人员服务
peopleService,err:=people.NewService(ctx,option.WithAPIKey(GoogleAPIKey))
如果错误!=零{
返回GoogleUser{},错误
}
//使用用户id定义资源名称
var resourceName string=fmt.Sprintf(“people/%s”,userId)
//获取用户配置文件
profile,err:=peopleService.People.Get(resourceName.PersonFields(“名称,照片”).Do()
如果错误!=零{
返回GoogleUser{},错误
}
log.Debug()。
接口(“配置文件”,配置文件)。
发送()
返回Google用户{Name:profile.Name[0]。显示名称,电子邮件:userEmail,照片Url:profile.Photos[0]。Url},无
}

标题
X-Goog-Authenticated-User-Email
作为请求标题从IAP发送到后端,而不是作为响应标题发送到客户端。客户端收到了身份验证cookies。@约翰汉利我也在某处读到过。我正在添加一条日志消息来仔细检查值。有些乏味,因为这无法在本地开发机器上测试,必须部署到IAP所在的生产环境中。不过我会测试一下。谢谢您在IAP后面使用哪种服务?我使用新服务的一个技巧是从标题和环境变量创建一个HTML表,然后将其作为响应发送回去。这使我能够查看发送到诸如Cloud Run或App Engine之类的服务的所有标题。在部署了一个简单的/headers路由(通过它们循环并写入ResponseWriter)后,我现在可以查看这些标题
X-Goog-Authenticated-User-Id
X-Goog-Authenticated-User-Email
X-Goog-Iap-Jwt-Assertion