Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
祺技世界
gin-vue-admin
提交
01d8a3d1
G
gin-vue-admin
项目概览
祺技世界
/
gin-vue-admin
与 Fork 源项目一致
Fork自
FLIPPED-AURORA / gin-vue-admin
通知
6
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
gin-vue-admin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
01d8a3d1
编写于
8月 17, 2020
作者:
Mr.奇淼(
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加令牌自动续期功能
上级
a84767b4
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
62 addition
and
55 deletion
+62
-55
server/api/v1/sys_user.go
server/api/v1/sys_user.go
+5
-5
server/middleware/jwt.go
server/middleware/jwt.go
+37
-21
server/model/request/jwt.go
server/model/request/jwt.go
+2
-0
server/service/jwt_black_list.go
server/service/jwt_black_list.go
+7
-4
web/src/permission.js
web/src/permission.js
+0
-8
web/src/store/module/user.js
web/src/store/module/user.js
+1
-10
web/src/utils/request.js
web/src/utils/request.js
+10
-7
未找到文件。
server/api/v1/sys_user.go
浏览文件 @
01d8a3d1
...
...
@@ -88,10 +88,12 @@ func tokenNext(c *gin.Context, user model.SysUser) {
UUID
:
user
.
UUID
,
ID
:
user
.
ID
,
NickName
:
user
.
NickName
,
Username
:
user
.
Username
,
AuthorityId
:
user
.
AuthorityId
,
BufferTime
:
60
*
60
*
24
,
// 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
StandardClaims
:
jwt
.
StandardClaims
{
NotBefore
:
time
.
Now
()
.
Unix
()
-
1000
,
// 签名生效时间
ExpiresAt
:
time
.
Now
()
.
Unix
()
+
60
*
60
*
24
*
7
,
// 过期时间
一周
ExpiresAt
:
time
.
Now
()
.
Unix
()
+
60
*
60
*
24
*
7
,
// 过期时间
7天
Issuer
:
"qmPlus"
,
// 签名的发行者
},
}
...
...
@@ -108,11 +110,9 @@ func tokenNext(c *gin.Context, user model.SysUser) {
},
c
)
return
}
var
loginJwt
model
.
JwtBlacklist
loginJwt
.
Jwt
=
token
err
,
jwtStr
:=
service
.
GetRedisJWT
(
user
.
Username
)
if
err
==
redis
.
Nil
{
if
err
:=
service
.
SetRedisJWT
(
loginJwt
,
user
.
Username
);
err
!=
nil
{
if
err
:=
service
.
SetRedisJWT
(
token
,
user
.
Username
);
err
!=
nil
{
response
.
FailWithMessage
(
"设置登录状态失败"
,
c
)
return
}
...
...
@@ -130,7 +130,7 @@ func tokenNext(c *gin.Context, user model.SysUser) {
response
.
FailWithMessage
(
"jwt作废失败"
,
c
)
return
}
if
err
:=
service
.
SetRedisJWT
(
loginJwt
,
user
.
Username
);
err
!=
nil
{
if
err
:=
service
.
SetRedisJWT
(
jwtStr
,
user
.
Username
);
err
!=
nil
{
response
.
FailWithMessage
(
"设置登录状态失败"
,
c
)
return
}
...
...
server/middleware/jwt.go
浏览文件 @
01d8a3d1
...
...
@@ -9,6 +9,7 @@ import (
"gin-vue-admin/service"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"strconv"
"time"
)
...
...
@@ -16,9 +17,6 @@ func JWTAuth() gin.HandlerFunc {
return
func
(
c
*
gin
.
Context
)
{
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localSstorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
token
:=
c
.
Request
.
Header
.
Get
(
"x-token"
)
modelToken
:=
model
.
JwtBlacklist
{
Jwt
:
token
,
}
if
token
==
""
{
response
.
Result
(
response
.
ERROR
,
gin
.
H
{
"reload"
:
true
,
...
...
@@ -26,7 +24,7 @@ func JWTAuth() gin.HandlerFunc {
c
.
Abort
()
return
}
if
service
.
IsBlacklist
(
token
,
modelToken
)
{
if
service
.
IsBlacklist
(
token
)
{
response
.
Result
(
response
.
ERROR
,
gin
.
H
{
"reload"
:
true
,
},
"您的帐户异地登陆或令牌失效"
,
c
)
...
...
@@ -50,6 +48,24 @@ func JWTAuth() gin.HandlerFunc {
c
.
Abort
()
return
}
if
claims
.
ExpiresAt
-
time
.
Now
()
.
Unix
()
<
claims
.
BufferTime
{
claims
.
ExpiresAt
=
time
.
Now
()
.
Unix
()
+
60
*
60
*
24
*
7
newToken
,
_
:=
j
.
CreateToken
(
*
claims
)
newClaims
,
_
:=
j
.
ParseToken
(
newToken
)
c
.
Header
(
"new-token"
,
newToken
)
c
.
Header
(
"new-expires-at"
,
strconv
.
FormatInt
(
newClaims
.
ExpiresAt
,
10
))
if
global
.
GVA_CONFIG
.
System
.
UseMultipoint
{
err
,
RedisJwtToken
:=
service
.
GetRedisJWT
(
newClaims
.
Username
)
if
err
!=
nil
{
global
.
GVA_LOG
.
Error
(
err
)
}
else
{
service
.
JsonInBlacklist
(
model
.
JwtBlacklist
{
Jwt
:
RedisJwtToken
})
//当之前的取成功时才进行拉黑操作
}
// 无论如何都要记录当前的活跃状态
_
=
service
.
SetRedisJWT
(
newToken
,
newClaims
.
Username
)
}
}
c
.
Set
(
"claims"
,
claims
)
c
.
Next
()
}
...
...
@@ -111,20 +127,20 @@ func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) {
}
// 更新token
func
(
j
*
JWT
)
RefreshToken
(
tokenString
string
)
(
string
,
error
)
{
jwt
.
TimeFunc
=
func
()
time
.
Time
{
return
time
.
Unix
(
0
,
0
)
}
token
,
err
:=
jwt
.
ParseWithClaims
(
tokenString
,
&
request
.
CustomClaims
{},
func
(
token
*
jwt
.
Token
)
(
interface
{},
error
)
{
return
j
.
SigningKey
,
nil
})
if
err
!=
nil
{
return
""
,
err
}
if
claims
,
ok
:=
token
.
Claims
.
(
*
request
.
CustomClaims
);
ok
&&
token
.
Valid
{
jwt
.
TimeFunc
=
time
.
Now
claims
.
StandardClaims
.
ExpiresAt
=
time
.
Now
()
.
Add
(
1
*
time
.
Hour
)
.
Unix
()
return
j
.
CreateToken
(
*
claims
)
}
return
""
,
TokenInvalid
}
//
func (j *JWT) RefreshToken(tokenString string) (string, error) {
//
jwt.TimeFunc = func() time.Time {
//
return time.Unix(0, 0)
//
}
//
token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
//
return j.SigningKey, nil
//
})
//
if err != nil {
//
return "", err
//
}
//
if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
//
jwt.TimeFunc = time.Now
// claims.StandardClaims.ExpiresAt = time.Now().Unix() + 60*60*24*7
//
return j.CreateToken(*claims)
//
}
//
return "", TokenInvalid
//
}
server/model/request/jwt.go
浏览文件 @
01d8a3d1
...
...
@@ -9,7 +9,9 @@ import (
type
CustomClaims
struct
{
UUID
uuid
.
UUID
ID
uint
Username
string
NickName
string
AuthorityId
string
BufferTime
int64
jwt
.
StandardClaims
}
server/service/jwt_black_list.go
浏览文件 @
01d8a3d1
...
...
@@ -3,6 +3,7 @@ package service
import
(
"gin-vue-admin/global"
"gin-vue-admin/model"
"time"
)
// @title JsonInBlacklist
...
...
@@ -23,8 +24,8 @@ func JsonInBlacklist(jwtList model.JwtBlacklist) (err error) {
// @param jwtList model.JwtBlacklist
// @return err error
func
IsBlacklist
(
jwt
string
,
jwtList
model
.
JwtBlacklist
)
bool
{
isNotFound
:=
global
.
GVA_DB
.
Where
(
"jwt = ?"
,
jwt
)
.
First
(
&
jwtList
)
.
RecordNotFound
()
func
IsBlacklist
(
jwt
string
)
bool
{
isNotFound
:=
global
.
GVA_DB
.
Where
(
"jwt = ?"
,
jwt
)
.
First
(
&
model
.
JwtBlacklist
{}
)
.
RecordNotFound
()
return
!
isNotFound
}
...
...
@@ -47,7 +48,9 @@ func GetRedisJWT(userName string) (err error, redisJWT string) {
// @param userName string
// @return err error
func
SetRedisJWT
(
jwtList
model
.
JwtBlacklist
,
userName
string
)
(
err
error
)
{
err
=
global
.
GVA_REDIS
.
Set
(
userName
,
jwtList
.
Jwt
,
1000
*
1000
*
1000
*
60
*
60
*
24
*
7
)
.
Err
()
func
SetRedisJWT
(
jwt
string
,
userName
string
)
(
err
error
)
{
// 此处过期时间等于jwt过期时间
timer
:=
60
*
60
*
24
*
7
*
time
.
Second
err
=
global
.
GVA_REDIS
.
Set
(
userName
,
jwt
,
timer
)
.
Err
()
return
err
}
web/src/permission.js
浏览文件 @
01d8a3d1
...
...
@@ -7,14 +7,6 @@ const whiteList = ['login', 'register']
router
.
beforeEach
(
async
(
to
,
from
,
next
)
=>
{
const
token
=
store
.
getters
[
'
user/token
'
]
// if (token) {
// const expiresAt = store.getters['user/expiresAt']
// const nowUnix = new Date().getTime()
// const hasExpires = (expiresAt - nowUnix) < 0
// if (hasExpires) {
// store.dispatch['user/claerAll']
// }
// }
// 在白名单中的判断情况
if
(
whiteList
.
indexOf
(
to
.
name
)
>
-
1
)
{
if
(
token
)
{
...
...
web/src/store/module/user.js
浏览文件 @
01d8a3d1
...
...
@@ -11,7 +11,6 @@ export const user = {
authority
:
""
,
},
token
:
""
,
expiresAt
:
""
},
mutations
:
{
setUserInfo
(
state
,
userInfo
)
{
...
...
@@ -22,14 +21,9 @@ export const user = {
// 这里的 `state` 对象是模块的局部状态
state
.
token
=
token
},
setExpiresAt
(
state
,
expiresAt
)
{
// 这里的 `state` 对象是模块的局部状态
state
.
expiresAt
=
expiresAt
},
LoginOut
(
state
)
{
state
.
userInfo
=
{}
state
.
token
=
""
state
.
expiresAt
=
""
router
.
push
({
name
:
'
login
'
,
replace
:
true
})
sessionStorage
.
clear
()
window
.
location
.
reload
()
...
...
@@ -45,7 +39,6 @@ export const user = {
const
res
=
await
login
(
loginInfo
)
commit
(
'
setUserInfo
'
,
res
.
data
.
user
)
commit
(
'
setToken
'
,
res
.
data
.
token
)
commit
(
'
setExpiresAt
'
,
res
.
data
.
expiresAt
)
if
(
res
.
code
==
0
)
{
const
redirect
=
router
.
history
.
current
.
query
.
redirect
if
(
redirect
)
{
...
...
@@ -69,8 +62,6 @@ export const user = {
token
(
state
)
{
return
state
.
token
},
expiresAt
(
state
)
{
return
state
.
expiresAt
}
}
}
\ No newline at end of file
web/src/utils/request.js
浏览文件 @
01d8a3d1
...
...
@@ -21,13 +21,13 @@ const showLoading = () => {
}
const
closeLoading
=
()
=>
{
acitveAxios
--
if
(
acitveAxios
<=
0
)
{
clearTimeout
(
timer
)
loadingInstance
&&
loadingInstance
.
close
()
acitveAxios
--
if
(
acitveAxios
<=
0
)
{
clearTimeout
(
timer
)
loadingInstance
&&
loadingInstance
.
close
()
}
}
}
//http request 拦截器
//http request 拦截器
service
.
interceptors
.
request
.
use
(
config
=>
{
showLoading
()
...
...
@@ -37,7 +37,7 @@ service.interceptors.request.use(
config
.
headers
=
{
'
Content-Type
'
:
'
application/json
'
,
'
x-token
'
:
token
,
'
x-user-id
'
:
user
.
ID
'
x-user-id
'
:
user
.
ID
}
return
config
;
},
...
...
@@ -57,6 +57,9 @@ service.interceptors.request.use(
service
.
interceptors
.
response
.
use
(
response
=>
{
closeLoading
()
if
(
response
.
headers
[
"
new-token
"
])
{
store
.
commit
(
'
user/setToken
'
,
response
.
headers
[
"
new-token
"
])
}
if
(
response
.
data
.
code
==
0
||
response
.
headers
.
success
===
"
true
"
)
{
return
response
.
data
}
else
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录