Skip to content

Commit

Permalink
add refreshing token config
Browse files Browse the repository at this point in the history
  • Loading branch information
LyricTian committed Nov 16, 2016
1 parent 8193204 commit 3044539
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 66 deletions.
33 changes: 20 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"net/http"

"gopkg.in/oauth2.v3/manage"
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/server"
"gopkg.in/oauth2.v3/store"
)
Expand All @@ -52,8 +53,15 @@ func main() {
manager := manage.NewDefaultManager()
// token memory store
manager.MustTokenStorage(store.NewMemoryTokenStore())
// client test store
manager.MapClientStorage(store.NewTestClientStore())

// client memory store
clientStore := store.NewClientStore()
clientStore.Set("000000", &models.Client{
ID: "000000",
Secret: "999999",
Domain: "http://localhost",
})
manager.MapClientStorage(clientStore)

srv := server.NewDefaultServer(manager)
srv.SetAllowGetAccessRequest(true)
Expand All @@ -76,7 +84,6 @@ func main() {

http.ListenAndServe(":9096", nil)
}

```

### Build and run
Expand All @@ -89,12 +96,12 @@ $ ./server
### Open in your web browser

```
http://localhost:9096/token?grant_type=client_credentials&client_id=1&client_secret=11&scope=read
http://localhost:9096/token?grant_type=client_credentials&client_id=000000&client_secret=999999&scope=read
```

``` json
{
"access_token": "ACPT7UYYNVWS2OAPFOHVUW",
"access_token": "J86XVRYSNFCFI233KXDL0Q",
"expires_in": 7200,
"scope": "read",
"token_type": "Bearer"
Expand All @@ -103,12 +110,12 @@ http://localhost:9096/token?grant_type=client_credentials&client_id=1&client_sec

## Features

* Easy to use
* Based on the [RFC 6749](https://tools.ietf.org/html/rfc6749) implementation
* Token storage support TTL
* Support custom extension field
* Support custom scope
* Support custom expiration time of the access token
* easy to use
* based on the [RFC 6749](https://tools.ietf.org/html/rfc6749) implementation
* token storage support TTL
* support custom expiration time of the access token
* support custom extension field
* support custom scope

## Example

Expand All @@ -132,8 +139,8 @@ Copyright (c) 2016 Lyric
[License-Image]: https://img.shields.io/npm/l/express.svg
[Build-Status-Url]: https://travis-ci.org/go-oauth2/oauth2
[Build-Status-Image]: https://travis-ci.org/go-oauth2/oauth2.svg?branch=master
[Release-Url]: https://github.com/go-oauth2/oauth2/releases/tag/v3.5.3
[Release-image]: http://img.shields.io/badge/release-v3.5.3-1eb0fc.svg
[Release-Url]: https://github.com/go-oauth2/oauth2/releases/tag/v3.6.0
[Release-image]: http://img.shields.io/badge/release-v3.6.0-1eb0fc.svg
[ReportCard-Url]: https://goreportcard.com/report/gopkg.in/oauth2.v3
[ReportCard-Image]: https://goreportcard.com/badge/gopkg.in/oauth2.v3
[GoDoc-Url]: https://godoc.org/gopkg.in/oauth2.v3
Expand Down
12 changes: 6 additions & 6 deletions example/server/server.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"fmt"
"log"
"net/http"
"net/url"
Expand All @@ -11,7 +10,6 @@ import (
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/server"
"gopkg.in/oauth2.v3/store"

"gopkg.in/session.v1"
)

Expand All @@ -28,17 +26,19 @@ func main() {
manager := manage.NewDefaultManager()
// token store
manager.MustTokenStorage(store.NewMemoryTokenStore())
// client store
manager.MapClientStorage(store.NewTestClientStore(&models.Client{

clientStore := store.NewClientStore()
clientStore.Set("222222", &models.Client{
ID: "222222",
Secret: "22222222",
Domain: "http://localhost:9094",
}))
})
manager.MapClientStorage(clientStore)

srv := server.NewServer(server.NewConfig(), manager)
srv.SetUserAuthorizationHandler(userAuthorizeHandler)
srv.SetInternalErrorHandler(func(err error) {
fmt.Println("internal error:", err.Error())
log.Println("[oauth2] error:", err.Error())
})

http.HandleFunc("/login", loginHandler)
Expand Down
14 changes: 12 additions & 2 deletions manage/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,18 @@ type Config struct {
RefreshTokenExp time.Duration
// whether to generate the refreshing token
IsGenerateRefresh bool
// whether to reset the refreshing expiration time
}

// RefreshingConfig refreshing token config
type RefreshingConfig struct {
// whether to generate the refreshing token
IsGenerateRefresh bool
// whether to reset the refreshing create time
IsResetRefreshTime bool
// whether to remove access token
IsRemoveAccess bool
// whether to remove refreshing token
IsRemoveRefreshing bool
}

// default configs
Expand All @@ -21,5 +31,5 @@ var (
DefaultImplicitTokenCfg = &Config{AccessTokenExp: time.Hour * 1}
DefaultPasswordTokenCfg = &Config{AccessTokenExp: time.Hour * 2, RefreshTokenExp: time.Hour * 24 * 7, IsGenerateRefresh: true}
DefaultClientTokenCfg = &Config{AccessTokenExp: time.Hour * 2}
DefaultRefreshTokenCfg = &Config{}
DefaultRefreshTokenCfg = &RefreshingConfig{IsRemoveAccess: true, IsRemoveRefreshing: true}
)
34 changes: 22 additions & 12 deletions manage/manage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"gopkg.in/oauth2.v3"
"gopkg.in/oauth2.v3/manage"
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/store"

. "github.com/smartystreets/goconvey/convey"
Expand All @@ -13,9 +14,24 @@ import (
func TestManager(t *testing.T) {
Convey("Manager test", t, func() {
manager := manage.NewDefaultManager()
manager.MapClientStorage(store.NewTestClientStore())

manager.MustTokenStorage(store.NewMemoryTokenStore())

clientStore := store.NewClientStore()
clientStore.Set("1", &models.Client{
ID: "1",
Secret: "11",
Domain: "http://localhost",
})
manager.MapClientStorage(clientStore)

tgr := &oauth2.TokenGenerateRequest{
ClientID: "1",
UserID: "123456",
RedirectURI: "http://localhost/oauth2",
Scope: "all",
}

Convey("CheckInterface test", func() {
err := manager.CheckInterface()
So(err, ShouldBeNil)
Expand All @@ -28,28 +44,22 @@ func TestManager(t *testing.T) {
})

Convey("Token test", func() {
testManager(manager)
testManager(tgr, manager)
})
})
}

func testManager(manager oauth2.Manager) {
reqParams := &oauth2.TokenGenerateRequest{
ClientID: "1",
UserID: "123456",
RedirectURI: "http://localhost/oauth2",
Scope: "all",
}
cti, err := manager.GenerateAuthToken(oauth2.Code, reqParams)
func testManager(tgr *oauth2.TokenGenerateRequest, manager oauth2.Manager) {
cti, err := manager.GenerateAuthToken(oauth2.Code, tgr)
So(err, ShouldBeNil)

code := cti.GetCode()
So(code, ShouldNotBeEmpty)

atParams := &oauth2.TokenGenerateRequest{
ClientID: reqParams.ClientID,
ClientID: tgr.ClientID,
ClientSecret: "11",
RedirectURI: reqParams.RedirectURI,
RedirectURI: tgr.RedirectURI,
Code: code,
}
ati, err := manager.GenerateAccessToken(oauth2.AuthorizationCode, atParams)
Expand Down
31 changes: 21 additions & 10 deletions manage/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Manager struct {
injector inject.Injector
codeExp time.Duration
gtcfg map[oauth2.GrantType]*Config
rcfg *RefreshingConfig
validateURI ValidateURIHandler
}

Expand All @@ -52,8 +53,6 @@ func (m *Manager) grantConfig(gt oauth2.GrantType) *Config {
return DefaultPasswordTokenCfg
case oauth2.ClientCredentials:
return DefaultClientTokenCfg
case oauth2.Refreshing:
return DefaultRefreshTokenCfg
}
return &Config{}
}
Expand Down Expand Up @@ -84,8 +83,8 @@ func (m *Manager) SetClientTokenCfg(cfg *Config) {
}

// SetRefreshTokenCfg set the refreshing token config
func (m *Manager) SetRefreshTokenCfg(cfg *Config) {
m.gtcfg[oauth2.Refreshing] = cfg
func (m *Manager) SetRefreshTokenCfg(cfg *RefreshingConfig) {
m.rcfg = cfg
}

// SetValidateURIHandler set the validates that RedirectURI is contained in baseURI
Expand Down Expand Up @@ -282,6 +281,7 @@ func (m *Manager) GenerateAccessToken(gt oauth2.GrantType, tgr *oauth2.TokenGene
tgr.AccessTokenExp = exp
}
}

cli, err := m.GetClient(tgr.ClientID)
if err != nil {
return
Expand All @@ -297,6 +297,7 @@ func (m *Manager) GenerateAccessToken(gt oauth2.GrantType, tgr *oauth2.TokenGene
CreateAt: time.Now(),
}
gcfg := m.grantConfig(gt)

av, rv, terr := gen.Token(td, gcfg.IsGenerateRefresh)
if terr != nil {
err = terr
Expand Down Expand Up @@ -358,7 +359,10 @@ func (m *Manager) RefreshAccessToken(tgr *oauth2.TokenGenerateRequest) (accessTo
CreateAt: time.Now(),
}

rcfg := m.grantConfig(oauth2.Refreshing)
rcfg := DefaultRefreshTokenCfg
if v := m.rcfg; v != nil {
rcfg = v
}

tv, rv, terr := gen.Token(td, rcfg.IsGenerateRefresh)
if terr != nil {
Expand All @@ -368,26 +372,33 @@ func (m *Manager) RefreshAccessToken(tgr *oauth2.TokenGenerateRequest) (accessTo

ti.SetAccess(tv)
ti.SetAccessCreateAt(td.CreateAt)

if rcfg.IsResetRefreshTime {
ti.SetRefreshCreateAt(td.CreateAt)
}

if scope := tgr.Scope; scope != "" {
ti.SetScope(scope)
}

if rv != "" {
ti.SetRefresh(rv)
}

if verr := stor.Create(ti); verr != nil {
err = verr
return
}

// remove the old access token
if verr := stor.RemoveByAccess(oldAccess); verr != nil {
err = verr
return
if rcfg.IsRemoveAccess {
// remove the old access token
if verr := stor.RemoveByAccess(oldAccess); verr != nil {
err = verr
return
}
}
if rv != "" {

if rcfg.IsRemoveRefreshing && rv != "" {
// remove the old refresh token
if verr := stor.RemoveByRefresh(oldRefresh); verr != nil {
err = verr
Expand Down
5 changes: 3 additions & 2 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ func init() {
}

func clientStore(domain string) oauth2.ClientStore {
return store.NewTestClientStore(&models.Client{
clientStore := store.NewClientStore()
clientStore.Set(clientID, &models.Client{
ID: clientID,
Secret: clientSecret,
Domain: domain,
})
return clientStore
}

func testServer(t *testing.T, w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -221,7 +223,6 @@ func TestRefreshing(t *testing.T) {
defer csrv.Close()

manager.MapClientStorage(clientStore(csrv.URL))
manager.SetRefreshTokenCfg(&manage.Config{IsGenerateRefresh: false})
srv = server.NewDefaultServer(manager)
srv.SetUserAuthorizationHandler(func(w http.ResponseWriter, r *http.Request) (userID string, err error) {
userID = "000000"
Expand Down
45 changes: 24 additions & 21 deletions store/client.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
package store

import (
"errors"
"sync"

"gopkg.in/oauth2.v3"
"gopkg.in/oauth2.v3/models"
)

// NewTestClientStore create to client information store instance
func NewTestClientStore(clients ...*models.Client) oauth2.ClientStore {
data := map[string]*models.Client{
"1": &models.Client{
ID: "1",
Secret: "11",
Domain: "http://localhost",
UserID: "000000",
},
}
for _, cli := range clients {
data[cli.ID] = cli
}
return &TestClientStore{
data: data,
func NewClientStore() *ClientStore {
return &ClientStore{
data: make(map[string]oauth2.ClientInfo),
}
}

// TestClientStore client information store
type TestClientStore struct {
data map[string]*models.Client
// ClientStore client information store
type ClientStore struct {
sync.RWMutex
data map[string]oauth2.ClientInfo
}

// GetByID according to the ID for the client information
func (ts *TestClientStore) GetByID(id string) (cli oauth2.ClientInfo, err error) {
if c, ok := ts.data[id]; ok {
func (cs *ClientStore) GetByID(id string) (cli oauth2.ClientInfo, err error) {
cs.RLock()
defer cs.RUnlock()
if c, ok := cs.data[id]; ok {
cli = c
return
}
err = errors.New("not found")
return
}

// Set set client information
func (cs *ClientStore) Set(id string, cli oauth2.ClientInfo) (err error) {
cs.Lock()
defer cs.Unlock()
cs.data[id] = cli
return
}
Loading

0 comments on commit 3044539

Please sign in to comment.