當我們平常像下面這樣透過Google OAuth進行登入時,點選登入後會需要有一個Redirect URI,只要Google驗證通過後,就會重新導向去打該網址,讓自己的後端能接收到使用者登入後的資訊~
所以我們需要做一個新的Handler,來專門處理OAuth Login後的資訊~
在router資料夾下先建立oauth.go
我們需要import google提供的以下套件
// oauth.go
import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/drive/v3" //go get google.golang.org/api/drive/v3
)
寫上用來處理登入後的OAuthLogin
,用一樣的方式,接受一個app作為參數,並回傳一個HandlerFunc
,這邊先把功能寫在這做測試,之後再移出去。
// oauth.go
func OAuthLogin(app *app.Application) gin.HandlerFunc {
return func(c *gin.Context) {
// 從 URL 參數中獲取授權碼
authCode := c.Query("code")
// 建立 OAuth2 Config
config := &oauth2.Config{
ClientID: os.Getenv("ClientID"),
ClientSecret: os.Getenv("ClientSecret"), // from https://console.developers.google.com/project/<your-project-id>/apiui/credential
Endpoint: google.Endpoint,
Scopes: []string{drive.DriveScope},
RedirectURL: os.Getenv("RedirectURL"),
}
// 交換授權碼以獲取token
tok, err := config.Exchange(context.TODO(), authCode)
if err != nil {
log.Printf("Unable to retrieve token from web %v", err)
}
// 使用token初始化 Google Drive 服務
client := config.Client(context.Background(), tok)
srv, err := drive.NewService(c, option.WithHTTPClient(client))
if err != nil {
log.Printf("Unable to retrieve Drive client: %v", err)
}
// 列出 Google Drive 上的文件
r, err := srv.Files.List().PageSize(10).
Fields("nextPageToken, files(id, name)").Do()
if err != nil {
log.Printf("Unable to retrieve files: %v", err)
}
fmt.Println("Files:")
if len(r.Files) == 0 {
fmt.Println("No files found.")
} else {
for _, i := range r.Files {
fmt.Printf("%s (%s)\n", i.Name, i.Id)
}
}
// 將 HTML 寫入回應,顯示授權成功的消息
_, err = c.Writer.Write([]byte("<html><title>Login</title> <body> Authorized successfully, please close this window</body></html>"))
if err != nil {
log.Printf("Unable to write HTML: %v", err)
}
}
}
我們上面寫了一個簡單的範例,執行以下的動作
- 從 URL 參數中獲取授權碼
authCode
,這是 Google OAuth 登入頁面成功後,重新導向時帶回來的參數。- 我們一樣從env讀取參數創建一個
oauth2.Config
實例。- 使用
config.Exchange
方法交換授權碼authCode
來獲取存取令牌tok
。- 使用取得的存取令牌初始化一個 Google Drive 服務的
drive.Service
實例。- 使用
srv.Files.List()
方法列出 Google Drive 上的文件,並列出文件的名稱和 ID。- 最後,顯示一個簡單的 HTML ,表達授權成功。
最後,我們到v1.go註冊寫好的路由~
func RegisterRouter(router *gin.RouterGroup, app *app.Application) {
v1 := router.Group("/v1")
{
v1.POST("/callback", Callback(app))
v1.GET("/ouath-login", OAuthLogin(app))
}
}
這樣就完成OAuth Login的部分了,那我們今天就先寫到這,明天見~