Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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