Skip to content

Commit dfa2a93

Browse files
author
raul-brainattica
committed
Token Logout - Redis black list.
1 parent 7f49849 commit dfa2a93

File tree

5 files changed

+100
-4
lines changed

5 files changed

+100
-4
lines changed

controllers/auth_controller.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"api.jwt.auth/core/authentication"
66
"api.jwt.auth/services/models"
77
"encoding/json"
8+
"fmt"
9+
jwt "github.com/dgrijalva/jwt-go"
810
"net/http"
911
)
1012

@@ -19,6 +21,7 @@ func Login(w http.ResponseWriter, r *http.Request) {
1921
token := parameters.TokenAuthentication{authBackend.GenerateToken()}
2022
response, _ := json.Marshal(token)
2123
w.Header().Set("Content-Type", "application/json")
24+
w.WriteHeader(http.StatusOK)
2225
w.Write(response)
2326

2427
} else {
@@ -37,5 +40,21 @@ func RefresfhToken(w http.ResponseWriter, r *http.Request, next http.HandlerFunc
3740
}
3841

3942
func Logout(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
40-
w.Write([]byte("Unauthorized"))
43+
authBackend := authentication.InitJWTAuthenticationBackend()
44+
token, err := jwt.ParseFromRequest(r, func(token *jwt.Token) (interface{}, error) {
45+
return authBackend.PublicKey, nil
46+
})
47+
tokenString := r.Header.Get("Authorization")
48+
49+
err = authBackend.Logout(tokenString, token)
50+
51+
w.Header().Set("Content-Type", "application/json")
52+
if err != nil {
53+
fmt.Println(http.StatusInternalServerError)
54+
fmt.Println(err)
55+
w.WriteHeader(http.StatusInternalServerError)
56+
} else {
57+
fmt.Println(http.StatusOK)
58+
w.WriteHeader(http.StatusOK)
59+
}
4160
}

core/authentication/jwt_backend.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
package authentication
22

33
import (
4+
"api.jwt.auth/core/redis"
45
"api.jwt.auth/services/models"
56
jwt "github.com/dgrijalva/jwt-go"
67
"golang.org/x/crypto/bcrypt"
78
"io/ioutil"
89
"path/filepath"
10+
"time"
911
)
1012

1113
type JWTAuthenticationBackend struct {
1214
privateKey []byte
1315
PublicKey []byte
1416
}
1517

18+
const (
19+
tokenDuration = 72
20+
expireOffset = 3600
21+
)
22+
1623
func InitJWTAuthenticationBackend() *JWTAuthenticationBackend {
1724
authBack := new(JWTAuthenticationBackend)
1825
privateKeyPath, _ := filepath.Abs("./core/authentication/keys/private_key")
@@ -25,6 +32,7 @@ func InitJWTAuthenticationBackend() *JWTAuthenticationBackend {
2532

2633
func (backend *JWTAuthenticationBackend) GenerateToken() string {
2734
token := jwt.New(jwt.GetSigningMethod("RS256"))
35+
token.Claims["exp"] = time.Now().Add(time.Hour * time.Duration(tokenDuration)).Unix()
2836
tokenString, _ := token.SignedString(backend.privateKey)
2937
return tokenString
3038
}
@@ -40,6 +48,29 @@ func (backend *JWTAuthenticationBackend) Authenticate(user *models.User) bool {
4048
return user.Username == testUser.Username && bcrypt.CompareHashAndPassword([]byte(testUser.Password), []byte(user.Password)) == nil
4149
}
4250

43-
func (backend *JWTAuthenticationBackend) Logout(token string) error {
44-
return nil
51+
func (backend *JWTAuthenticationBackend) getTokenRemainingValidity(timestamp interface{}) int {
52+
if validity, ok := timestamp.(float64); ok {
53+
tm := time.Unix(int64(validity), 0)
54+
remainer := tm.Sub(time.Now())
55+
if remainer > 0 {
56+
return int(remainer.Seconds() + expireOffset)
57+
}
58+
}
59+
return expireOffset
60+
}
61+
62+
func (backend *JWTAuthenticationBackend) Logout(tokenString string, token *jwt.Token) error {
63+
redisConn := redis.Connect()
64+
return redisConn.SetValue(tokenString, tokenString, backend.getTokenRemainingValidity(token.Claims["exp"]))
65+
}
66+
67+
func (backend *JWTAuthenticationBackend) IsInBlacklist(token string) bool {
68+
redisConn := redis.Connect()
69+
redisToken, _ := redisConn.GetValue(token)
70+
71+
if redisToken == nil {
72+
return false
73+
}
74+
75+
return true
4576
}

core/authentication/middlewares.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ func RequireTokenAuthentication(rw http.ResponseWriter, req *http.Request, next
1212
return authBackend.PublicKey, nil
1313
})
1414

15-
if err == nil && token.Valid {
15+
if err == nil && token.Valid && !authBackend.IsInBlacklist(req.Header.Get("Authorization")) {
1616
next(rw, req)
1717
} else {
1818
rw.WriteHeader(http.StatusUnauthorized)

core/redis/redis_cli.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package redis
2+
3+
import (
4+
"github.com/garyburd/redigo/redis"
5+
)
6+
7+
type RedisCli struct {
8+
conn redis.Conn
9+
}
10+
11+
var instanceRedisCli *RedisCli = nil
12+
13+
func Connect() (conn *RedisCli) {
14+
if instanceRedisCli == nil {
15+
instanceRedisCli = new(RedisCli)
16+
var err error
17+
18+
instanceRedisCli.conn, err = redis.Dial("tcp", ":6379")
19+
20+
if err != nil {
21+
panic(err)
22+
}
23+
24+
if _, err := instanceRedisCli.conn.Do("AUTH", "Brainattica"); err != nil {
25+
instanceRedisCli.conn.Close()
26+
panic(err)
27+
}
28+
}
29+
30+
return instanceRedisCli
31+
}
32+
33+
func (redisCli *RedisCli) SetValue(key string, value string, expiration ...interface{}) error {
34+
_, err := redisCli.conn.Do("SET", key, value)
35+
36+
if err == nil && expiration != nil {
37+
redisCli.conn.Do("EXPIRE", key, expiration[0])
38+
}
39+
40+
return err
41+
}
42+
43+
func (redisCli *RedisCli) GetValue(key string) (interface{}, error) {
44+
return redisCli.conn.Do("GET", key)
45+
}

routers/authentication.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ import (
1010
func SetAuthenticationRoutes(router *mux.Router) *mux.Router {
1111
router.HandleFunc("/token-auth", controllers.Login).Methods("POST")
1212
router.Handle("/refresh-token-auth", negroni.New(negroni.HandlerFunc(authentication.RequireTokenAuthentication), negroni.HandlerFunc(controllers.RefresfhToken))).Methods("GET")
13+
router.Handle("/logout", negroni.New(negroni.HandlerFunc(authentication.RequireTokenAuthentication), negroni.HandlerFunc(controllers.Logout))).Methods("GET")
1314
return router
1415
}

0 commit comments

Comments
 (0)