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.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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,9 @@ export default {
|
||||
password: '密码',
|
||||
any: '随便填',
|
||||
thirdparty: '第三方登录',
|
||||
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
|
||||
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!',
|
||||
expires: '登录token过期,请重新登录',
|
||||
tokenError: 'token错误,请重新登录'
|
||||
},
|
||||
commons: {
|
||||
upload: '上传',
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
})
|
||||
|
@ -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()
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user