0

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

获取用户的身份中,它声明有X-Goog-Authenticated-User-EmailX-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 结构获得,但我如何从 IAP 获取这些信息?

4

1 回答 1

0

在@JohnHanley 提到只有在 IAP 后面运行时才会显示标头后,我才能够完成这项工作。在本地开发过程中您看不到它们。

在部署一个简单的临时路由后,我可以看到它们,/headers该路由循环通过它们并写入 ResponseWriter。 X-Goog-Authenticated-User-Id,X-Goog-Authenticated-User-EmailX-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

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

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

结构:

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, "accounts.google.com:", "")
    }

    // 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())
    }
}

谷歌人员 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
}
于 2021-04-06T14:30:22.160 回答