如何存储访问令牌以供重用?

时间:2016-06-26 16:01:36

标签: go oauth

我使用go的oauth2包代表用户向Instagram发出请求。我要弄清楚的唯一部分是如何存储访问/刷新令牌,然后如何再次使用oauth2?这是我到目前为止的代码,它所做的就是获取访问令牌并向API发出一个请求。之后,我不知道该怎么做。

package main

import "net/http"
import "io/ioutil"
import "fmt"
import "html/template"
import "golang.org/x/oauth2"

var ClientID = YOUR_CLIENT_ID

var ClientSecret = YOUR_CLIENT_SECRET
var RedirectURI = "http://localhost:8080/redirect"

var authURL = "https://api.instagram.com/oauth/authorize"

var tokenURL = "https://api.instagram.com/oauth/access_token"

var templ = template.Must(template.New("index.html").ParseFiles("index.html"))

var igConf *oauth2.Config

func redirect(res http.ResponseWriter, req *http.Request) {

    code := req.FormValue("code")

    if len(code) != 0 {
        tok, err := igConf.Exchange(oauth2.NoContext, code)
        if err != nil {
            fmt.Println(err)
            http.NotFound(res, req)
            return
        }

        if tok.Valid() {
            client := igConf.Client(oauth2.NoContext, tok)

            request, err := http.NewRequest("GET", "https://api.instagram.com/v1/users/self/?access_token="+tok.AccessToken, nil)
            if err != nil {
                fmt.Println(err)
                http.NotFound(res, req)
                return
            }

            resp, err := client.Do(request)
            if err != nil {
                fmt.Println(err)
                http.NotFound(res, req)
                return
            }
            defer resp.Body.Close()

            body, err := ioutil.ReadAll(resp.Body)
            if err != nil {
                fmt.Println(err)
                http.NotFound(res, req)
                return
            }

            res.Write(body)
        }

        http.NotFound(res, req)
    }

}

func homePage(res http.ResponseWriter, req *http.Request) {
    url := igConf.AuthCodeURL("", oauth2.AccessTypeOffline)
    fmt.Println(url)
    err := templ.Execute(res, url)
    if err != nil {
        fmt.Println(err)
    }
}

func main() {
    igConf = &oauth2.Config{
        ClientID:     ClientID,
        ClientSecret: ClientSecret,
        Endpoint: oauth2.Endpoint{
            AuthURL:  authURL,
            TokenURL: tokenURL,
        },
        RedirectURL: RedirectURI,
        Scopes:      []string{"public_content", "comments"},
    }

    http.HandleFunc("/redirect", redirect)
    http.HandleFunc("/", homePage)
    http.ListenAndServe(":8080", nil)
}

3 个答案:

答案 0 :(得分:3)

您可以将访问令牌存储在Cookie中,方法是在<p id="color"> </p>函数的res.Write(body)行之前插入以下代码:

redirect()

在其他一些处理程序中,你会再次读回这个令牌:

res.SetCookie(&Cookie{
   Name: "access_token",
   Value: tok.AccessToken,
   Expires: time.Now().Add(time.Hour * 24), // expires in 24 hours
}

答案 1 :(得分:0)

为什么要存储访问令牌?

访问和刷新令牌都是承载令牌,应按照RFC 6750中的定义进行处理。

当他们回来并再次点击登录按钮时,您通常只需重新执行授权流程。

如果您存储令牌,则需要担心保护令牌中的数据,这些令牌可以访问有关您用户的一些相当特权的信息。

我建议您尽可能转到OpenID Connect以及使用JWT加密和签名的地方。

-Jim

答案 2 :(得分:0)

您好,我为令牌存储和管理编写了一个模块,该模块具有到期时间的延迟,请看一下该模块,我认为它可以帮助您, 我从中间件调用此存储来管理令牌

 # storage.go
 package token_store

 import (
     "sync"
     "time"
 )

 type item struct {
    token      string
    lastAccess int64
 }

 // storage structure to managing the store tokens
 type Storage struct {
     storeMap map[string]*item
     lock     sync.Mutex
 }

 func NewStore(len, expireTime int64) (s *Storage) {
     // initial the storage
     s = &Store{storeMap: make(map[string]*item, len)}
     go func() {
         // each minute check that token has expired or not
         for now := range time.Tick(time.Minute) {
             // lock the cache for updating the values
             s.lock.Lock()
             for key, value := range s.storeMap {
                 /*
                     if expiration time exceeded then start to removing
                     the token from cache
                 */
                 if now.Unix()-value.lastAccess > expireTime {
                    delete(s.storeMap, key)
                 }
             }
             s.lock.Unlock()
         }
     }()
     return
 }

 func (s *Storage) Len() int {
    // return the len of storage map
    return len(s.storeMap)
 }

func (s *Storage) Put(key, value string) {
    /*
        value will be the authentication token
        key can be user-name or anay things that you
        want to access token within it
    */
    s.lock.Lock()
    if it, ok := s.storeMap[key]; !ok { // if token is not exist
        it = &item{value, time.Now().Unix()}
        s.storeMap[key] = it
    } else { // if token exist then update the last access time
        it.lastAccess = time.Now().Unix()
    }
    s.lock.Unlock()

 }

 func (s *Storage) Get(key string) (value string) {
     /*
         check out hte item
     */
     s.lock.Lock()
     if item, ok := s.storeMap[key]; ok { // check if item exist then pass the value
          value = item.token
          item.lastAccess = time.Now().Unix()
     }
     s.lock.Unlock()
     return
 }

我希望这篇文章对您有所帮助。