Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d8a260f

Browse files
add redis cluster support
1 parent de39c2c commit d8a260f

File tree

6 files changed

+293
-175
lines changed

6 files changed

+293
-175
lines changed

‎.travis.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
language: go
2+
sudo: false
3+
go_import_path: gopkg.in/go-oauth2/redis.v3
4+
go:
5+
- 1.9
6+
services:
7+
- redis-server
8+
before_install:
9+
- go get -t -v ./...
10+
11+
script:
12+
- go test -race -coverprofile=coverage.txt -covermode=atomic
13+
14+
after_success:
15+
- bash <(curl -s https://codecov.io/bash)

‎README.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
# Redis Storage for OAuth 2.0
1+
# Redis Storage for [OAuth 2.0](https://github.com/go-oauth2/oauth2)
22

3-
> Based on the redis token storage
4-
5-
[![License][License-Image]][License-Url]
6-
[![ReportCard][ReportCard-Image]][ReportCard-Url]
7-
[![GoDoc][GoDoc-Image]][GoDoc-Url]
3+
[![Build][Build-Status-Image]][Build-Status-Url] [![Codecov][codecov-image]][codecov-url] [![ReportCard][reportcard-image]][reportcard-url] [![GoDoc][godoc-image]][godoc-url] [![License][license-image]][license-url]
84

95
## Install
106

117
``` bash
12-
$ go get -u -v gopkg.in/go-oauth2/redis.v1
8+
$ go get -u -v gopkg.in/go-oauth2/redis.v3
139
```
1410

1511
## Usage
@@ -18,18 +14,21 @@ $ go get -u -v gopkg.in/go-oauth2/redis.v1
1814
package main
1915

2016
import (
21-
"gopkg.in/go-oauth2/redis.v1"
17+
"gopkg.in/go-oauth2/redis.v3"
2218
"gopkg.in/oauth2.v3/manage"
2319
)
2420

2521
func main() {
2622
manager := manage.NewDefaultManager()
23+
2724
// use redis token store
28-
manager.MustTokenStorage(redis.NewTokenStore(&redis.Config{
25+
manager.MustTokenStorage(redis.NewRedisStore(&redis.Options{
2926
Addr: "127.0.0.1:6379",
27+
DB: 15,
3028
}))
3129

32-
// ...
30+
// use redis cluster store
31+
// redis.NewRedisClusterStore()
3332
}
3433
```
3534

@@ -39,9 +38,13 @@ func main() {
3938
Copyright (c) 2016 Lyric
4039
```
4140

42-
[License-Url]: http://opensource.org/licenses/MIT
43-
[License-Image]: https://img.shields.io/npm/l/express.svg
44-
[ReportCard-Url]: https://goreportcard.com/report/github.com/go-oauth2/redis
45-
[ReportCard-Image]: https://goreportcard.com/badge/github.com/go-oauth2/redis
46-
[GoDoc-Url]: https://godoc.org/github.com/go-oauth2/redis
47-
[GoDoc-Image]: https://godoc.org/github.com/go-oauth2/redis?status.svg
41+
[Build-Status-Url]: https://travis-ci.org/go-oauth2/redis
42+
[Build-Status-Image]: https://travis-ci.org/go-oauth2/redis.svg?branch=master
43+
[codecov-url]: https://codecov.io/gh/go-oauth2/redis
44+
[codecov-image]: https://codecov.io/gh/go-oauth2/redis/branch/master/graph/badge.svg
45+
[reportcard-url]: https://goreportcard.com/report/gopkg.in/go-oauth2/redis.v3
46+
[reportcard-image]: https://goreportcard.com/badge/gopkg.in/go-oauth2/redis.v3
47+
[godoc-url]: https://godoc.org/gopkg.in/go-oauth2/redis.v3
48+
[godoc-image]: https://godoc.org/gopkg.in/go-oauth2/redis.v3?status.svg
49+
[license-url]: http://opensource.org/licenses/MIT
50+
[license-image]: https://img.shields.io/npm/l/express.svg

‎config.go renamed to ‎options.go

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
"github.com/go-redis/redis"
99
)
1010

11-
// Config Redis parameter options
12-
type Config struct {
11+
// Options Redis parameter options
12+
type Options struct {
1313
// The network type, either tcp or unix.
1414
// Default is tcp.
1515
Network string
@@ -68,7 +68,7 @@ type Config struct {
6868
TLSConfig *tls.Config
6969
}
7070

71-
func (o *Config) redisOptions() *redis.Options {
71+
func (o *Options) redisOptions() *redis.Options {
7272
return &redis.Options{
7373
Network: o.Network,
7474
Addr: o.Addr,
@@ -88,3 +88,63 @@ func (o *Config) redisOptions() *redis.Options {
8888
TLSConfig: o.TLSConfig,
8989
}
9090
}
91+
92+
// ClusterOptions are used to configure a cluster client and should be
93+
// passed to NewClusterClient.
94+
type ClusterOptions struct {
95+
// A seed list of host:port addresses of cluster nodes.
96+
Addrs []string
97+
98+
// The maximum number of retries before giving up. Command is retried
99+
// on network errors and MOVED/ASK redirects.
100+
// Default is 8.
101+
MaxRedirects int
102+
103+
// Enables read-only commands on slave nodes.
104+
ReadOnly bool
105+
// Allows routing read-only commands to the closest master or slave node.
106+
RouteByLatency bool
107+
// Allows routing read-only commands to the random master or slave node.
108+
RouteRandomly bool
109+
110+
// Following options are copied from Options struct.
111+
112+
OnConnect func(*redis.Conn) error
113+
114+
MaxRetries int
115+
MinRetryBackoff time.Duration
116+
MaxRetryBackoff time.Duration
117+
Password string
118+
119+
DialTimeout time.Duration
120+
ReadTimeout time.Duration
121+
WriteTimeout time.Duration
122+
123+
// PoolSize applies per cluster node and not for the whole cluster.
124+
PoolSize int
125+
PoolTimeout time.Duration
126+
IdleTimeout time.Duration
127+
IdleCheckFrequency time.Duration
128+
}
129+
130+
func (o *ClusterOptions) redisClusterOptions() *redis.ClusterOptions {
131+
return &redis.ClusterOptions{
132+
Addrs: o.Addrs,
133+
MaxRedirects: o.MaxRedirects,
134+
ReadOnly: o.ReadOnly,
135+
RouteByLatency: o.RouteByLatency,
136+
RouteRandomly: o.RouteRandomly,
137+
OnConnect: o.OnConnect,
138+
MaxRetries: o.MaxRetries,
139+
MinRetryBackoff: o.MinRetryBackoff,
140+
MaxRetryBackoff: o.MaxRetryBackoff,
141+
Password: o.Password,
142+
DialTimeout: o.DialTimeout,
143+
ReadTimeout: o.ReadTimeout,
144+
WriteTimeout: o.WriteTimeout,
145+
PoolSize: o.PoolSize,
146+
PoolTimeout: o.PoolTimeout,
147+
IdleTimeout: o.IdleTimeout,
148+
IdleCheckFrequency: o.IdleCheckFrequency,
149+
}
150+
}

‎redis.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package redis
2+
3+
import (
4+
"time"
5+
6+
"github.com/go-redis/redis"
7+
"github.com/json-iterator/go"
8+
"gopkg.in/oauth2.v3"
9+
"gopkg.in/oauth2.v3/models"
10+
"gopkg.in/oauth2.v3/utils/uuid"
11+
)
12+
13+
var (
14+
_ oauth2.TokenStore = &TokenStore{}
15+
jsonMarshal = jsoniter.Marshal
16+
jsonUnmarshal = jsoniter.Unmarshal
17+
)
18+
19+
// NewRedisStore create an instance of a redis store
20+
func NewRedisStore(opts *Options) *TokenStore {
21+
if opts == nil {
22+
panic("options cannot be nil")
23+
}
24+
return NewRedisStoreWithCli(redis.NewClient(opts.redisOptions()))
25+
}
26+
27+
// NewRedisStoreWithCli create an instance of a redis store
28+
func NewRedisStoreWithCli(cli *redis.Client) *TokenStore {
29+
return &TokenStore{
30+
cli: cli,
31+
}
32+
}
33+
34+
// NewRedisClusterStore create an instance of a redis cluster store
35+
func NewRedisClusterStore(opts *ClusterOptions) *TokenStore {
36+
if opts == nil {
37+
panic("options cannot be nil")
38+
}
39+
return NewRedisClusterStoreWithCli(redis.NewClusterClient(opts.redisClusterOptions()))
40+
}
41+
42+
// NewRedisClusterStoreWithCli create an instance of a redis cluster store
43+
func NewRedisClusterStoreWithCli(cli *redis.ClusterClient) *TokenStore {
44+
return &TokenStore{
45+
cli: cli,
46+
}
47+
}
48+
49+
type clienter interface {
50+
Get(key string) *redis.StringCmd
51+
TxPipeline() redis.Pipeliner
52+
Del(keys ...string) *redis.IntCmd
53+
Close() error
54+
}
55+
56+
// TokenStore redis token store
57+
type TokenStore struct {
58+
cli clienter
59+
}
60+
61+
// Close close the store
62+
func (s *TokenStore) Close() error {
63+
return s.cli.Close()
64+
}
65+
66+
// Create Create and store the new token information
67+
func (s *TokenStore) Create(info oauth2.TokenInfo) (err error) {
68+
ct := time.Now()
69+
jv, err := jsonMarshal(info)
70+
if err != nil {
71+
return
72+
}
73+
74+
pipe := s.cli.TxPipeline()
75+
if code := info.GetCode(); code != "" {
76+
pipe.Set(code, jv, info.GetCodeExpiresIn())
77+
} else {
78+
basicID := uuid.Must(uuid.NewRandom()).String()
79+
aexp := info.GetAccessExpiresIn()
80+
rexp := aexp
81+
82+
if refresh := info.GetRefresh(); refresh != "" {
83+
rexp = info.GetRefreshCreateAt().Add(info.GetRefreshExpiresIn()).Sub(ct)
84+
if aexp.Seconds() > rexp.Seconds() {
85+
aexp = rexp
86+
}
87+
pipe.Set(refresh, basicID, rexp)
88+
}
89+
90+
pipe.Set(info.GetAccess(), basicID, aexp)
91+
pipe.Set(basicID, jv, rexp)
92+
}
93+
94+
if _, verr := pipe.Exec(); verr != nil {
95+
err = verr
96+
}
97+
return
98+
}
99+
100+
// remove
101+
func (s *TokenStore) remove(key string) (err error) {
102+
_, verr := s.cli.Del(key).Result()
103+
if verr != redis.Nil {
104+
err = verr
105+
}
106+
return
107+
}
108+
109+
// RemoveByCode Use the authorization code to delete the token information
110+
func (s *TokenStore) RemoveByCode(code string) (err error) {
111+
err = s.remove(code)
112+
return
113+
}
114+
115+
// RemoveByAccess Use the access token to delete the token information
116+
func (s *TokenStore) RemoveByAccess(access string) (err error) {
117+
err = s.remove(access)
118+
return
119+
}
120+
121+
// RemoveByRefresh Use the refresh token to delete the token information
122+
func (s *TokenStore) RemoveByRefresh(refresh string) (err error) {
123+
err = s.remove(refresh)
124+
return
125+
}
126+
127+
func (s *TokenStore) getData(key string) (ti oauth2.TokenInfo, err error) {
128+
result := s.cli.Get(key)
129+
if verr := result.Err(); verr != nil {
130+
if verr == redis.Nil {
131+
return
132+
}
133+
err = verr
134+
return
135+
}
136+
iv, err := result.Bytes()
137+
if err != nil {
138+
return
139+
}
140+
var tm models.Token
141+
if verr := jsonUnmarshal(iv, &tm); verr != nil {
142+
err = verr
143+
return
144+
}
145+
ti = &tm
146+
return
147+
}
148+
149+
func (s *TokenStore) getBasicID(token string) (basicID string, err error) {
150+
tv, verr := s.cli.Get(token).Result()
151+
if verr != nil {
152+
if verr == redis.Nil {
153+
return
154+
}
155+
err = verr
156+
return
157+
}
158+
basicID = tv
159+
return
160+
}
161+
162+
// GetByCode Use the authorization code for token information data
163+
func (s *TokenStore) GetByCode(code string) (ti oauth2.TokenInfo, err error) {
164+
ti, err = s.getData(code)
165+
return
166+
}
167+
168+
// GetByAccess Use the access token for token information data
169+
func (s *TokenStore) GetByAccess(access string) (ti oauth2.TokenInfo, err error) {
170+
basicID, err := s.getBasicID(access)
171+
if err != nil || basicID == "" {
172+
return
173+
}
174+
ti, err = s.getData(basicID)
175+
return
176+
}
177+
178+
// GetByRefresh Use the refresh token for token information data
179+
func (s *TokenStore) GetByRefresh(refresh string) (ti oauth2.TokenInfo, err error) {
180+
basicID, err := s.getBasicID(refresh)
181+
if err != nil || basicID == "" {
182+
return
183+
}
184+
ti, err = s.getData(basicID)
185+
return
186+
}

‎token_test.go renamed to ‎redis_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@ import (
44
"testing"
55
"time"
66

7-
"gopkg.in/go-oauth2/redis.v1"
7+
"gopkg.in/go-oauth2/redis.v3"
88
"gopkg.in/oauth2.v3/models"
99

1010
. "github.com/smartystreets/goconvey/convey"
1111
)
1212

13+
const (
14+
addr = "localhost:6379"
15+
db = 15
16+
)
17+
1318
func TestTokenStore(t *testing.T) {
1419
Convey("Test redis token store", t, func() {
15-
cfg := &redis.Config{
16-
Addr: "127.0.0.1:6379",
20+
opts := &redis.Options{
21+
Addr: addr,
22+
DB: db,
1723
}
18-
store, err := redis.NewTokenStore(cfg)
24+
store, err := redis.NewRedisStore(opts)
1925
So(err, ShouldBeNil)
2026

2127
Convey("Test authorization code store", func() {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /