feat: 长时间无操作则token自动失效

This commit is contained in:
fit2cloud-chenyw 2021-03-10 14:25:26 +08:00
parent 2a766461ca
commit e5941ee58b
7 changed files with 67 additions and 30 deletions

View File

@ -6,6 +6,9 @@ import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.service.AuthUserService;
import io.dataease.auth.util.JWTUtils;
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.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
@ -23,6 +26,8 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
public final static String expireMessage = "login token is expire";
/*@Autowired
private AuthUserService authUserService;*/
@ -46,7 +51,10 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
// 当没有出现登录超时 且需要刷新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);
}
JWTToken token = new JWTToken(authorization);
@ -67,7 +75,12 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
boolean loginSuccess = executeLogin(request, response);
return loginSuccess;
} catch (Exception e) {
response401(request, response);
if (e instanceof AuthenticationException && StringUtils.equals(e.getMessage(), expireMessage)){
responseExpire(request, response);
}else {
response401(request, response);
}
}
}
return false;
@ -129,4 +142,16 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
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());
}
}
}

View File

@ -6,23 +6,23 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.filter.JWTFilter;
import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.commons.utils.ServletUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
public class JWTUtils {
// token过期时间5min (过期会自动刷新续命 目的是避免一直都是同一个token )
private static final long EXPIRE_TIME = 1*60*1000;
// token过期时间1min (过期会自动刷新续命 目的是避免一直都是同一个token )
private static final long EXPIRE_TIME = 1*60*1000/2;
// 登录间隔时间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("userId", tokenInfo.getUserId())
.build();
DecodedJWT jwt = verifier.verify(token);
//Long lastLoginTime = jwt.getClaim("lastLoginTime").asLong();
Long lastOperateTime = tokenLastOperateTime(token);
long now = System.currentTimeMillis();
if (now - lastOperateTime > Login_Interval){
verifier.verify(token);
if (loginExpire(token)){
// 登录超时
HttpServletResponse response = ServletUtils.response();
response.addHeader("Access-Control-Expose-Headers", "authentication-status");
response.setHeader("authentication-status", "login_expire");
throw new AuthenticationException(JWTFilter.expireMessage);
// 前端拦截 登录超时状态 直接logout
return false;
//return false;
}
return true;
}
@ -143,6 +138,7 @@ public class JWTUtils {
public static void addTokenExpire(String token){
CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
Cache tokens_expire = cacheManager.getCache("tokens_expire");
tokens_expire.put(token, System.currentTimeMillis());
long now = System.currentTimeMillis();
tokens_expire.put(token, now);
}
}

View File

@ -80,7 +80,9 @@ export default {
password: '密码',
any: '随便填',
thirdparty: '第三方登录',
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!',
expires: '登录token过期请重新登录',
tokenError: 'token错误请重新登录'
},
commons: {
upload: '上传',

View File

@ -42,6 +42,9 @@ const mutations = {
},
SET_PERMISSIONS: (state, 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 => {
const { data } = response
commit('SET_TOKEN', data.token)
commit('SET_LOGIN_MSG', null)
setToken(data.token)
resolve()
}).catch(error => {
@ -117,6 +121,9 @@ const actions = {
commit('RESET_STATE')
resolve()
})
},
setLoginMsg({ commit, msg }) {
commit('SET_LOGIN_MSG', msg)
}
}

View File

@ -1,7 +1,7 @@
import { MessageBox, Message } from 'element-ui'
import i18n from '@/lang'
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(() => {
callback()
})
@ -9,12 +9,12 @@ export const $alert = (message, callback, options) => {
export const $confirm = (message, callback, options = {}) => {
const defaultOptions = {
confirmButtonText: this.$t('common.button.ok'),
cancelButtonText: this.$t('common.button.cancel'),
confirmButtonText: i18n.t('common.button.ok'),
cancelButtonText: i18n.t('common.button.cancel'),
type: 'warning',
...options
}
const title = this.$t('common.message_box.confirm')
const title = i18n.t('common.message_box.confirm')
MessageBox.confirm(message, title, defaultOptions).then(() => {
callback()
})

View File

@ -4,7 +4,7 @@ import store from '@/store'
import { $alert, $error } from './message'
import { getToken } from '@/utils/auth'
import Config from '@/settings'
import i18n from '@/lang'
import { tryShowLoading, tryHideLoading } from './loading'
// import router from '@/router'
@ -44,16 +44,19 @@ service.interceptors.request.use(
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, () => {
store.dispatch('user/logout').then(() => {
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, () => {
store.dispatch('user/logout').then(() => {
location.reload()

View File

@ -79,8 +79,12 @@ export default {
},
loading: false,
passwordType: 'password',
redirect: undefined,
msg: null
redirect: undefined
}
},
computed: {
msg() {
return this.$store.state.user.loginMsg
}
},
watch: {