<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 實現OAuth2令牌存儲接口 在上一個小節中,我們為客戶端檢索了一個令牌并執行了API請求。這種方法的缺點是我們的令牌沒有長期存儲空間。例如,在HTTP服務器中,我們希望在請求之間保持一致的令牌存儲。 本節將探討修改OAuth2客戶端以在請求之間存儲令牌并使用密鑰檢索它們。為簡單起見,此密鑰將是一個文件,但它也可以是數據庫,Redis等。 ### 實踐 1. 建立 config.go: ``` package oauthstore import ( "context" "net/http" "golang.org/x/oauth2" ) // Config 包含了 oauth2.Config和 Storage接口 type Config struct { *oauth2.Config Storage } // Exchange 在接收到令牌后將其存儲 func (c *Config) Exchange(ctx context.Context, code string) (*oauth2.Token, error) { token, err := c.Config.Exchange(ctx, code) if err != nil { return nil, err } if err := c.Storage.SetToken(token); err != nil { return nil, err } return token, nil } // TokenSource 可以傳遞已被存儲的令牌 // 或當新令牌被接收時將其轉換為oauth2.TokenSource func (c *Config) TokenSource(ctx context.Context, t *oauth2.Token) oauth2.TokenSource { return StorageTokenSource(ctx, c, t) } // Client 附加到TokenSource func (c *Config) Client(ctx context.Context, t *oauth2.Token) *http.Client { return oauth2.NewClient(ctx, c.TokenSource(ctx, t)) } ``` 2. 建立 tokensource.go: ``` package oauthstore import ( "context" "golang.org/x/oauth2" ) type storageTokenSource struct { *Config oauth2.TokenSource } // Token滿足TokenSource接口 func (s *storageTokenSource) Token() (*oauth2.Token, error) { if token, err := s.Config.Storage.GetToken(); err == nil && token.Valid() { return token, err } token, err := s.TokenSource.Token() if err != nil { return token, err } if err := s.Config.Storage.SetToken(token); err != nil { return nil, err } return token, nil } // StorageTokenSource 將由config.TokenSource方法調用 func StorageTokenSource(ctx context.Context, c *Config, t *oauth2.Token) oauth2.TokenSource { if t == nil || !t.Valid() { if tok, err := c.Storage.GetToken(); err == nil { t = tok } } ts := c.Config.TokenSource(ctx, t) return &storageTokenSource{c, ts} } ``` 3. 建立 storage.go: ``` package oauthstore import ( "context" "fmt" "golang.org/x/oauth2" ) // Storage 是我們的通用存儲接口 type Storage interface { GetToken() (*oauth2.Token, error) SetToken(*oauth2.Token) error } // GetToken 檢索github oauth2令牌 func GetToken(ctx context.Context, conf Config) (*oauth2.Token, error) { token, err := conf.Storage.GetToken() if err == nil && token.Valid() { return token, err } url := conf.AuthCodeURL("state") fmt.Printf("Type the following url into your browser and follow the directions on screen: %v\n", url) fmt.Println("Paste the code returned in the redirect URL and hit Enter:") var code string if _, err := fmt.Scan(&code); err != nil { return nil, err } return conf.Exchange(ctx, code) } ``` 4. 建立 filestorage.go: ``` package oauthstore import ( "encoding/json" "errors" "os" "sync" "golang.org/x/oauth2" ) // FileStorage 滿足storage 接口 type FileStorage struct { Path string mu sync.RWMutex } // GetToken 從文件中檢索令牌 func (f *FileStorage) GetToken() (*oauth2.Token, error) { f.mu.RLock() defer f.mu.RUnlock() in, err := os.Open(f.Path) if err != nil { return nil, err } defer in.Close() var t *oauth2.Token data := json.NewDecoder(in) return t, data.Decode(&t) } // SetToken 將令牌存儲在文件中 func (f *FileStorage) SetToken(t *oauth2.Token) error { if t == nil || !t.Valid() { return errors.New("bad token") } f.mu.Lock() defer f.mu.Unlock() out, err := os.OpenFile(f.Path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) if err != nil { return err } defer out.Close() data, err := json.Marshal(&t) if err != nil { return err } _, err = out.Write(data) return err } ``` 5. 建立 main.go: ``` package main import ( "context" "io" "os" "github.com/agtorre/go-cookbook/chapter6/oauthstore" "golang.org/x/oauth2" "golang.org/x/oauth2/github" ) func main() { conf := oauthstore.Config{ Config: &oauth2.Config{ ClientID: os.Getenv("GITHUB_CLIENT"), ClientSecret: os.Getenv("GITHUB_SECRET"), Scopes: []string{"repo", "user"}, Endpoint: github.Endpoint, }, Storage: &oauthstore.FileStorage{Path: "token.txt"}, } ctx := context.Background() token, err := oauthstore.GetToken(ctx, conf) if err != nil { panic(err) } cli := conf.Client(ctx, token) resp, err := cli.Get("https://api.github.com/user") if err != nil { panic(err) } defer resp.Body.Close() io.Copy(os.Stdout, resp.Body) } ``` 6. 這會輸出: ``` $ go run main.go Visit the URL for the auth dialog: https://github.com/login/oauth/authorize? access_type=offline&client_id= <your_id>&response_type=code&scope=repo+user&state=state Paste the code returned in the redirect URL and hit Enter: <your_code> {<json_payload>} $ go run main.go {<json_payload>} ``` ### 說明 本節將令牌的內容存儲到文件中并從文件中檢索令牌的內容。 如果是第一次運行,它必須執行整個代碼交換,但后續運行將重用訪問令牌,如果有可用,它將使用刷新令牌刷新。 此代碼中目前無法區分用戶/令牌,但這可以通過使用cookie作為文件名或數據庫中的行的鍵來實現。讓我們來看看這段代碼的作用: * config.go文件封裝了標準的OAuth2配置。對于涉及檢索令牌的每種方法,首先檢查本地存儲中是否有有效令牌。 如果沒有,使用標準配置檢索一個,然后存儲它。 * tokensource.go文件實現了與Config配對的自定義TokenSource接口。 與Config類似,總是首先嘗試從文件中檢索令牌,否則使用新令牌設置它。 * storage.go文件是Config和TokenSource使用的存儲接口。 它只定義了兩個方法和輔助函數來引導OAuth2基于代碼的流程,類似于我們在上一個方法中所做的那樣,但是如果已經存在具有有效令牌的文件,則將使用它。 * filestorage.go文件實現存儲接口。 當我們存儲新令牌時,首先截斷該文件并編寫令牌結構的JSON表示。 否則,我們解析文件并返回令牌。 * * * * 學識淺薄,錯誤在所難免。歡迎在群中就本書提出修改意見,以饗后來者,長風拜謝。 Golang中國(211938256) beego實戰(258969317) Go實踐(386056972)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看