Skip to content

Commit 0239f7b

Browse files
author
pixel
committed
增加令牌自动续期功能
1 parent 9679616 commit 0239f7b

File tree

7 files changed

+62
-55
lines changed

7 files changed

+62
-55
lines changed

server/api/v1/sys_user.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ func tokenNext(c *gin.Context, user model.SysUser) {
8888
UUID: user.UUID,
8989
ID: user.ID,
9090
NickName: user.NickName,
91+
Username: user.Username,
9192
AuthorityId: user.AuthorityId,
93+
BufferTime: 60*60*24, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
9294
StandardClaims: jwt.StandardClaims{
9395
NotBefore: time.Now().Unix() - 1000, // 签名生效时间
94-
ExpiresAt: time.Now().Unix() + 60*60*24*7, // 过期时间 一周
96+
ExpiresAt: time.Now().Unix() + 60*60*24*7, // 过期时间 7天
9597
Issuer: "qmPlus", // 签名的发行者
9698
},
9799
}
@@ -108,11 +110,9 @@ func tokenNext(c *gin.Context, user model.SysUser) {
108110
}, c)
109111
return
110112
}
111-
var loginJwt model.JwtBlacklist
112-
loginJwt.Jwt = token
113113
err, jwtStr := service.GetRedisJWT(user.Username)
114114
if err == redis.Nil {
115-
if err := service.SetRedisJWT(loginJwt, user.Username); err != nil {
115+
if err := service.SetRedisJWT(token, user.Username); err != nil {
116116
response.FailWithMessage("设置登录状态失败", c)
117117
return
118118
}
@@ -130,7 +130,7 @@ func tokenNext(c *gin.Context, user model.SysUser) {
130130
response.FailWithMessage("jwt作废失败", c)
131131
return
132132
}
133-
if err := service.SetRedisJWT(loginJwt, user.Username); err != nil {
133+
if err := service.SetRedisJWT(jwtStr, user.Username); err != nil {
134134
response.FailWithMessage("设置登录状态失败", c)
135135
return
136136
}

server/middleware/jwt.go

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,22 @@ import (
99
"gin-vue-admin/service"
1010
"github.com/dgrijalva/jwt-go"
1111
"github.com/gin-gonic/gin"
12+
"strconv"
1213
"time"
1314
)
1415

1516
func JWTAuth() gin.HandlerFunc {
1617
return func(c *gin.Context) {
1718
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localSstorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
1819
token := c.Request.Header.Get("x-token")
19-
modelToken := model.JwtBlacklist{
20-
Jwt: token,
21-
}
2220
if token == "" {
2321
response.Result(response.ERROR, gin.H{
2422
"reload": true,
2523
}, "未登录或非法访问", c)
2624
c.Abort()
2725
return
2826
}
29-
if service.IsBlacklist(token, modelToken) {
27+
if service.IsBlacklist(token) {
3028
response.Result(response.ERROR, gin.H{
3129
"reload": true,
3230
}, "您的帐户异地登陆或令牌失效", c)
@@ -50,6 +48,24 @@ func JWTAuth() gin.HandlerFunc {
5048
c.Abort()
5149
return
5250
}
51+
if claims.ExpiresAt - time.Now().Unix()<claims.BufferTime {
52+
claims.ExpiresAt = time.Now().Unix() + 60*60*24*7
53+
newToken,_ := j.CreateToken(*claims)
54+
newClaims,_ := j.ParseToken(newToken)
55+
c.Header("new-token",newToken)
56+
c.Header("new-expires-at",strconv.FormatInt(newClaims.ExpiresAt,10))
57+
if global.GVA_CONFIG.System.UseMultipoint {
58+
err,RedisJwtToken := service.GetRedisJWT(newClaims.Username)
59+
if err!=nil {
60+
global.GVA_LOG.Error(err)
61+
}else{
62+
service.JsonInBlacklist(model.JwtBlacklist{Jwt: RedisJwtToken})
63+
//当之前的取成功时才进行拉黑操作
64+
}
65+
// 无论如何都要记录当前的活跃状态
66+
_ = service.SetRedisJWT(newToken,newClaims.Username)
67+
}
68+
}
5369
c.Set("claims", claims)
5470
c.Next()
5571
}
@@ -111,20 +127,20 @@ func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) {
111127
}
112128

113129
// 更新token
114-
func (j *JWT) RefreshToken(tokenString string) (string, error) {
115-
jwt.TimeFunc = func() time.Time {
116-
return time.Unix(0, 0)
117-
}
118-
token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
119-
return j.SigningKey, nil
120-
})
121-
if err != nil {
122-
return "", err
123-
}
124-
if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
125-
jwt.TimeFunc = time.Now
126-
claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix()
127-
return j.CreateToken(*claims)
128-
}
129-
return "", TokenInvalid
130-
}
130+
//func (j *JWT) RefreshToken(tokenString string) (string, error) {
131+
// jwt.TimeFunc = func() time.Time {
132+
// return time.Unix(0, 0)
133+
// }
134+
// token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
135+
// return j.SigningKey, nil
136+
// })
137+
// if err != nil {
138+
// return "", err
139+
// }
140+
// if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
141+
// jwt.TimeFunc = time.Now
142+
// claims.StandardClaims.ExpiresAt = time.Now().Unix() + 60*60*24*7
143+
// return j.CreateToken(*claims)
144+
// }
145+
// return "", TokenInvalid
146+
//}

server/model/request/jwt.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
type CustomClaims struct {
1010
UUID uuid.UUID
1111
ID uint
12+
Username string
1213
NickName string
1314
AuthorityId string
15+
BufferTime int64
1416
jwt.StandardClaims
1517
}

server/service/jwt_black_list.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package service
33
import (
44
"gin-vue-admin/global"
55
"gin-vue-admin/model"
6+
"time"
67
)
78

89
// @title JsonInBlacklist
@@ -23,8 +24,8 @@ func JsonInBlacklist(jwtList model.JwtBlacklist) (err error) {
2324
// @param jwtList model.JwtBlacklist
2425
// @return err error
2526

26-
func IsBlacklist(jwt string, jwtList model.JwtBlacklist) bool {
27-
isNotFound := global.GVA_DB.Where("jwt = ?", jwt).First(&jwtList).RecordNotFound()
27+
func IsBlacklist(jwt string) bool {
28+
isNotFound := global.GVA_DB.Where("jwt = ?", jwt).First(&model.JwtBlacklist{}).RecordNotFound()
2829
return !isNotFound
2930
}
3031

@@ -47,7 +48,9 @@ func GetRedisJWT(userName string) (err error, redisJWT string) {
4748
// @param userName string
4849
// @return err error
4950

50-
func SetRedisJWT(jwtList model.JwtBlacklist, userName string) (err error) {
51-
err = global.GVA_REDIS.Set(userName, jwtList.Jwt, 1000*1000*1000*60*60*24*7).Err()
51+
func SetRedisJWT(jwt string, userName string) (err error) {
52+
// 此处过期时间等于jwt过期时间
53+
timer := 60*60*24*7*time.Second
54+
err = global.GVA_REDIS.Set(userName, jwt, timer).Err()
5255
return err
5356
}

web/src/permission.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,6 @@ const whiteList = ['login', 'register']
77

88
router.beforeEach(async(to, from, next) => {
99
const token = store.getters['user/token']
10-
// if (token) {
11-
// const expiresAt = store.getters['user/expiresAt']
12-
// const nowUnix = new Date().getTime()
13-
// const hasExpires = (expiresAt - nowUnix) < 0
14-
// if (hasExpires) {
15-
// store.dispatch['user/claerAll']
16-
// }
17-
// }
1810
// 在白名单中的判断情况
1911
if (whiteList.indexOf(to.name) > -1) {
2012
if (token) {

web/src/store/module/user.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export const user = {
1111
authority: "",
1212
},
1313
token: "",
14-
expiresAt: ""
1514
},
1615
mutations: {
1716
setUserInfo(state, userInfo) {
@@ -22,14 +21,9 @@ export const user = {
2221
// 这里的 `state` 对象是模块的局部状态
2322
state.token = token
2423
},
25-
setExpiresAt(state, expiresAt) {
26-
// 这里的 `state` 对象是模块的局部状态
27-
state.expiresAt = expiresAt
28-
},
2924
LoginOut(state) {
3025
state.userInfo = {}
3126
state.token = ""
32-
state.expiresAt = ""
3327
router.push({ name: 'login', replace: true })
3428
sessionStorage.clear()
3529
window.location.reload()
@@ -45,7 +39,6 @@ export const user = {
4539
const res = await login(loginInfo)
4640
commit('setUserInfo', res.data.user)
4741
commit('setToken', res.data.token)
48-
commit('setExpiresAt', res.data.expiresAt)
4942
if (res.code == 0) {
5043
const redirect = router.history.current.query.redirect
5144
if (redirect) {
@@ -69,8 +62,6 @@ export const user = {
6962
token(state) {
7063
return state.token
7164
},
72-
expiresAt(state) {
73-
return state.expiresAt
74-
}
65+
7566
}
7667
}

web/src/utils/request.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ const showLoading = () => {
2121
}
2222

2323
const closeLoading = () => {
24-
acitveAxios--
25-
if (acitveAxios <= 0) {
26-
clearTimeout(timer)
27-
loadingInstance && loadingInstance.close()
24+
acitveAxios--
25+
if (acitveAxios <= 0) {
26+
clearTimeout(timer)
27+
loadingInstance && loadingInstance.close()
28+
}
2829
}
29-
}
30-
//http request 拦截器
30+
//http request 拦截器
3131
service.interceptors.request.use(
3232
config => {
3333
showLoading()
@@ -37,7 +37,7 @@ service.interceptors.request.use(
3737
config.headers = {
3838
'Content-Type': 'application/json',
3939
'x-token': token,
40-
'x-user-id':user.ID
40+
'x-user-id': user.ID
4141
}
4242
return config;
4343
},
@@ -57,6 +57,9 @@ service.interceptors.request.use(
5757
service.interceptors.response.use(
5858
response => {
5959
closeLoading()
60+
if (response.headers["new-token"]) {
61+
store.commit('user/setToken', response.headers["new-token"])
62+
}
6063
if (response.data.code == 0 || response.headers.success === "true") {
6164
return response.data
6265
} else {

0 commit comments

Comments
 (0)