forked from github/dataease
feat: 长时间无操作则token自动失效
This commit is contained in:
parent
2a766461ca
commit
e5941ee58b
@ -6,6 +6,9 @@ import io.dataease.auth.entity.TokenInfo;
|
|||||||
import io.dataease.auth.service.AuthUserService;
|
import io.dataease.auth.service.AuthUserService;
|
||||||
import io.dataease.auth.util.JWTUtils;
|
import io.dataease.auth.util.JWTUtils;
|
||||||
import io.dataease.commons.utils.CommonBeanFactory;
|
import io.dataease.commons.utils.CommonBeanFactory;
|
||||||
|
import io.dataease.commons.utils.ServletUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -23,6 +26,8 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
|||||||
|
|
||||||
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
|
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
public final static String expireMessage = "login token is expire";
|
||||||
|
|
||||||
/*@Autowired
|
/*@Autowired
|
||||||
private AuthUserService authUserService;*/
|
private AuthUserService authUserService;*/
|
||||||
|
|
||||||
@ -46,7 +51,10 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
|||||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||||
String authorization = httpServletRequest.getHeader("Authorization");
|
String authorization = httpServletRequest.getHeader("Authorization");
|
||||||
// 当没有出现登录超时 且需要刷新token 则执行刷新token
|
// 当没有出现登录超时 且需要刷新token 则执行刷新token
|
||||||
if (!JWTUtils.loginExpire(authorization) && JWTUtils.needRefresh(authorization)){
|
if (JWTUtils.loginExpire(authorization)){
|
||||||
|
throw new AuthenticationException(expireMessage);
|
||||||
|
}
|
||||||
|
if (JWTUtils.needRefresh(authorization)){
|
||||||
authorization = refreshToken(request, response);
|
authorization = refreshToken(request, response);
|
||||||
}
|
}
|
||||||
JWTToken token = new JWTToken(authorization);
|
JWTToken token = new JWTToken(authorization);
|
||||||
@ -67,7 +75,12 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
|||||||
boolean loginSuccess = executeLogin(request, response);
|
boolean loginSuccess = executeLogin(request, response);
|
||||||
return loginSuccess;
|
return loginSuccess;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
response401(request, response);
|
if (e instanceof AuthenticationException && StringUtils.equals(e.getMessage(), expireMessage)){
|
||||||
|
responseExpire(request, response);
|
||||||
|
}else {
|
||||||
|
response401(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -129,4 +142,16 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
|||||||
LOGGER.error(e.getMessage());
|
LOGGER.error(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void responseExpire(ServletRequest req, ServletResponse resp) {
|
||||||
|
try {
|
||||||
|
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
|
||||||
|
httpServletResponse.addHeader("Access-Control-Expose-Headers", "authentication-status");
|
||||||
|
httpServletResponse.setHeader("authentication-status", "login_expire");
|
||||||
|
httpServletResponse.setStatus(401);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,23 @@ import com.auth0.jwt.algorithms.Algorithm;
|
|||||||
import com.auth0.jwt.exceptions.JWTDecodeException;
|
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
import io.dataease.auth.entity.TokenInfo;
|
import io.dataease.auth.entity.TokenInfo;
|
||||||
|
import io.dataease.auth.filter.JWTFilter;
|
||||||
import io.dataease.commons.utils.CommonBeanFactory;
|
import io.dataease.commons.utils.CommonBeanFactory;
|
||||||
import io.dataease.commons.utils.ServletUtils;
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
public class JWTUtils {
|
public class JWTUtils {
|
||||||
|
|
||||||
|
|
||||||
// token过期时间5min (过期会自动刷新续命 目的是避免一直都是同一个token )
|
// token过期时间1min (过期会自动刷新续命 目的是避免一直都是同一个token )
|
||||||
private static final long EXPIRE_TIME = 1*60*1000;
|
private static final long EXPIRE_TIME = 1*60*1000/2;
|
||||||
// 登录间隔时间10min 超过这个时间强制重新登录
|
// 登录间隔时间10min 超过这个时间强制重新登录
|
||||||
private static final long Login_Interval = 2*60*1000;
|
private static final long Login_Interval = 20*60*1000;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,17 +38,12 @@ public class JWTUtils {
|
|||||||
.withClaim("username", tokenInfo.getUsername())
|
.withClaim("username", tokenInfo.getUsername())
|
||||||
.withClaim("userId", tokenInfo.getUserId())
|
.withClaim("userId", tokenInfo.getUserId())
|
||||||
.build();
|
.build();
|
||||||
DecodedJWT jwt = verifier.verify(token);
|
verifier.verify(token);
|
||||||
//Long lastLoginTime = jwt.getClaim("lastLoginTime").asLong();
|
if (loginExpire(token)){
|
||||||
Long lastOperateTime = tokenLastOperateTime(token);
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (now - lastOperateTime > Login_Interval){
|
|
||||||
// 登录超时
|
// 登录超时
|
||||||
HttpServletResponse response = ServletUtils.response();
|
throw new AuthenticationException(JWTFilter.expireMessage);
|
||||||
response.addHeader("Access-Control-Expose-Headers", "authentication-status");
|
|
||||||
response.setHeader("authentication-status", "login_expire");
|
|
||||||
// 前端拦截 登录超时状态 直接logout
|
// 前端拦截 登录超时状态 直接logout
|
||||||
return false;
|
//return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -143,6 +138,7 @@ public class JWTUtils {
|
|||||||
public static void addTokenExpire(String token){
|
public static void addTokenExpire(String token){
|
||||||
CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
|
CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
|
||||||
Cache tokens_expire = cacheManager.getCache("tokens_expire");
|
Cache tokens_expire = cacheManager.getCache("tokens_expire");
|
||||||
tokens_expire.put(token, System.currentTimeMillis());
|
long now = System.currentTimeMillis();
|
||||||
|
tokens_expire.put(token, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,9 @@ export default {
|
|||||||
password: '密码',
|
password: '密码',
|
||||||
any: '随便填',
|
any: '随便填',
|
||||||
thirdparty: '第三方登录',
|
thirdparty: '第三方登录',
|
||||||
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
|
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!',
|
||||||
|
expires: '登录token过期,请重新登录',
|
||||||
|
tokenError: 'token错误,请重新登录'
|
||||||
},
|
},
|
||||||
commons: {
|
commons: {
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
|
@ -42,6 +42,9 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
SET_PERMISSIONS: (state, permissions) => {
|
SET_PERMISSIONS: (state, permissions) => {
|
||||||
state.permissions = permissions
|
state.permissions = permissions
|
||||||
|
},
|
||||||
|
SET_LOGIN_MSG: (state, msg) => {
|
||||||
|
state.loginMsg = msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +56,7 @@ const actions = {
|
|||||||
login({ username: username.trim(), password: password }).then(response => {
|
login({ username: username.trim(), password: password }).then(response => {
|
||||||
const { data } = response
|
const { data } = response
|
||||||
commit('SET_TOKEN', data.token)
|
commit('SET_TOKEN', data.token)
|
||||||
|
commit('SET_LOGIN_MSG', null)
|
||||||
setToken(data.token)
|
setToken(data.token)
|
||||||
resolve()
|
resolve()
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -117,6 +121,9 @@ const actions = {
|
|||||||
commit('RESET_STATE')
|
commit('RESET_STATE')
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
setLoginMsg({ commit, msg }) {
|
||||||
|
commit('SET_LOGIN_MSG', msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MessageBox, Message } from 'element-ui'
|
import { MessageBox, Message } from 'element-ui'
|
||||||
|
import i18n from '@/lang'
|
||||||
export const $alert = (message, callback, options) => {
|
export const $alert = (message, callback, options) => {
|
||||||
const title = this.$t('common.message_box.alert')
|
const title = i18n.t('common.message_box.alert')
|
||||||
MessageBox.alert(message, title, options).then(() => {
|
MessageBox.alert(message, title, options).then(() => {
|
||||||
callback()
|
callback()
|
||||||
})
|
})
|
||||||
@ -9,12 +9,12 @@ export const $alert = (message, callback, options) => {
|
|||||||
|
|
||||||
export const $confirm = (message, callback, options = {}) => {
|
export const $confirm = (message, callback, options = {}) => {
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
confirmButtonText: this.$t('common.button.ok'),
|
confirmButtonText: i18n.t('common.button.ok'),
|
||||||
cancelButtonText: this.$t('common.button.cancel'),
|
cancelButtonText: i18n.t('common.button.cancel'),
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
...options
|
...options
|
||||||
}
|
}
|
||||||
const title = this.$t('common.message_box.confirm')
|
const title = i18n.t('common.message_box.confirm')
|
||||||
MessageBox.confirm(message, title, defaultOptions).then(() => {
|
MessageBox.confirm(message, title, defaultOptions).then(() => {
|
||||||
callback()
|
callback()
|
||||||
})
|
})
|
||||||
|
@ -4,7 +4,7 @@ import store from '@/store'
|
|||||||
import { $alert, $error } from './message'
|
import { $alert, $error } from './message'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
import Config from '@/settings'
|
import Config from '@/settings'
|
||||||
|
import i18n from '@/lang'
|
||||||
import { tryShowLoading, tryHideLoading } from './loading'
|
import { tryShowLoading, tryHideLoading } from './loading'
|
||||||
// import router from '@/router'
|
// import router from '@/router'
|
||||||
|
|
||||||
@ -44,16 +44,19 @@ service.interceptors.request.use(
|
|||||||
|
|
||||||
const checkAuth = response => {
|
const checkAuth = response => {
|
||||||
// 请根据实际需求修改
|
// 请根据实际需求修改
|
||||||
if (response.headers['authentication-status'] === 'invalid' || response.status === 401) {
|
|
||||||
const message = this.$t('login.expires')
|
if (response.headers['authentication-status'] === 'login_expire') {
|
||||||
|
const message = i18n.t('login.expires')
|
||||||
|
store.dispatch('user/setLoginMsg', message)
|
||||||
$alert(message, () => {
|
$alert(message, () => {
|
||||||
store.dispatch('user/logout').then(() => {
|
store.dispatch('user/logout').then(() => {
|
||||||
location.reload()
|
location.reload()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (response.headers['authentication-status'] === 'login_expire') {
|
|
||||||
const message = this.$t('login.expires')
|
if (response.headers['authentication-status'] === 'invalid' || response.status === 401) {
|
||||||
|
const message = i18n.t('login.tokenError')
|
||||||
$alert(message, () => {
|
$alert(message, () => {
|
||||||
store.dispatch('user/logout').then(() => {
|
store.dispatch('user/logout').then(() => {
|
||||||
location.reload()
|
location.reload()
|
||||||
|
@ -79,8 +79,12 @@ export default {
|
|||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
passwordType: 'password',
|
passwordType: 'password',
|
||||||
redirect: undefined,
|
redirect: undefined
|
||||||
msg: null
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
msg() {
|
||||||
|
return this.$store.state.user.loginMsg
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
Loading…
Reference in New Issue
Block a user