今天一開始我們先來調整一下我們之前對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
,雖然是有辦法轉換,但為了漂亮一點我們還是來改一下宣告。
先到adapter/dynamodb/oauth.go
找到我們宣告的GoogleOAuthToken
,將Expiry
從string
改成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"`
}
接著到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。
我們到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
}
最後我們回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
}
...
重新OAuth Login,讓Dynamodb存有我們新的token後,我們到linebot list一下,可以看到成功的從Dynamodb查詢到token並且能順利取得Google Drive的資料了~
那今天就先寫到這邊,大家連假愉快,我們明天見~