iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0

今天一開始我們先來調整一下我們之前對Expiry宣告的類型,昨天仔細看發現oauth官方的Token(oauth2.Token)結構如下:

type Token struct {
	// AccessToken is the token that authorizes and authenticates
	// the requests.
	AccessToken string `json:"access_token"`

	// TokenType is the type of token.
	// The Type method returns either this or "Bearer", the default.
	TokenType string `json:"token_type,omitempty"`

	// RefreshToken is a token that's used by the application
	// (as opposed to the user) to refresh the access token
	// if it expires.
	RefreshToken string `json:"refresh_token,omitempty"`

	// Expiry is the optional expiration time of the access token.
	//
	// If zero, TokenSource implementations will reuse the same
	// token forever and RefreshToken or equivalent
	// mechanisms for that TokenSource will not be used.
	Expiry time.Time `json:"expiry,omitempty"`

	// raw optionally contains extra metadata from the server
	// when updating a token.
	raw interface{}

	// expiryDelta is used to calculate when a token is considered
	// expired, by subtracting from Expiry. If zero, defaultExpiryDelta
	// is used.
	expiryDelta time.Duration
}

他的Expiry是存time.Time,但是我們在dynamodb存的確是string,雖然是有辦法轉換,但為了漂亮一點我們還是來改一下宣告。

  1. 先到adapter/dynamodb/oauth.go找到我們宣告的GoogleOAuthToken,將Expirystring改成time.Time,這樣各個欄位存進去之前的類型就與oauth2的類型一致了。

    // internal\adapter\dynamodb\oauth.go
    type GoogleOAuthToken struct {
    	PK           string    `dynamodbav:"PK"`
    	AccessToken  string    `dynamodbav:"access_token"`
    	TokenType    string    `dynamodbav:"token_type"`
    	RefreshToken string    `dynamodbav:"refresh_token"`
    	Expiry       time.Time `dynamodbav:"expiry"`
    }
    
  2. 接著到drive service的login_service.go,我們把Expiry從tok.Expiry.String()換成tok.Expiry,這樣就好囉。

    // internal\app\service\drive\login_service.go
    func (dr *GoogleDriveService) Login(ctx context.Context, lineID string, authCode string) error {
    	tok, err := dr.driveServiceGoogleOA.UserOAuthToken(authCode)
    	if err != nil {
    		return err
    	}
    	dToken := dynamodb.GoogleOAuthToken{
    		PK:           lineID,
    		AccessToken:  tok.AccessToken,
    		TokenType:    tok.TokenType,
    		RefreshToken: tok.RefreshToken,
    		Expiry:       tok.Expiry,
    	}
    	err = dr.driveServiceDynamodb.AddGoogleOAuthToken(dToken)
    	if err != nil {
    		return err
    	}
    	return nil
    }
    

接著我們來嘗試從Dynamodb取得token,並用取出來的token調用使用者的Google drive。

  1. 我們到drive service的drive_service.go,把ListFiles的輸入從原本的authCode改成lineID。原本透過dr.driveServiceGoogleOA.UserOAuthToken(authCode)去Google取得token,我們現在換成透過lineID從Dynamodb查詢上次登入儲存的token。

    // internal\app\service\drive\drive_service.go
    func (dr *GoogleDriveService) ListFiles(ctx context.Context, lineID string) (map[string]string, error) {
    	// token改成去db取
    	dToken, err := dr.driveServiceDynamodb.GetGoogleOAuthToken(lineID)
    	if err != nil {
    		log.Println(err)
    		return nil, err
    	}
    	// 把token轉成oauth2的格式
    	tok := oauth2.Token{
    		AccessToken:  dToken.AccessToken,
    		TokenType:    dToken.TokenType,
    		RefreshToken: dToken.RefreshToken,
    		Expiry:       dToken.Expiry,
    	}
    	d, err := dr.driveServiceGoogleOA.NewGoogleDrive(ctx, &tok)
    	if err != nil {
    		log.Println(err)
    		return nil, err
    	}
    
    	result, err := d.ListFiles(10)
    	if err != nil {
    		log.Println(err)
    		return nil, err
    	}
    
    	return result, nil
    }
    
  2. 最後我們回Callback,加入message.Text == "list"的條件來測試,取得lineID後丟到DriveService.ListFiles,並把取得到的資料清單,直接印出來後回傳。

    // internal\router\api\v1\callback.go
    func Callback(app *app.Application) gin.HandlerFunc {
    ...
    for _, event := range events {
    			if event.Type == linebot.EventTypeMessage {
    				switch message := event.Message.(type) {
    				case *linebot.TextMessage:
    					if message.Text == "login" {
    						lineID := event.Source.UserID
    						authURL := app.DriveService.LoginURL(ctx, lineID)
    						if _, err = app.LineBotClient.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(authURL)).Do(); err != nil {
    							log.Println(err)
    						}
    						return
    					}
    					if message.Text == "list" {
    						lineID := event.Source.UserID
    						res, err := app.DriveService.ListFiles(ctx, lineID)
    						if err != nil {
    							log.Println(err)
    							return
    						}
    						if _, err = app.LineBotClient.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(fmt.Sprintln(res))).Do(); err != nil {
    							log.Println(err)
    						}
    						return
    					}
    ...
    
  3. 重新OAuth Login,讓Dynamodb存有我們新的token後,我們到linebot list一下,可以看到成功的從Dynamodb查詢到token並且能順利取得Google Drive的資料了~

    https://ithelp.ithome.com.tw/upload/images/20231006/20115990c2CW3f0ayO.png

那今天就先寫到這邊,大家連假愉快,我們明天見~


上一篇
Day20 Login Service - OAuth Token存到Dynamodb
下一篇
Day22 繞過 Google OAuth 在 User Agent 上的使用限制
系列文
Golang LineBot X GoogleDrive:LINE有各種限制!? 那就丟上Drive吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言