package com.vci.starter.web.interceptor;
|
|
|
import com.vci.starter.web.annotation.controller.VciUnCheckRight;
|
import com.vci.starter.web.autoconfigure.SpringMVCConfig;
|
import com.vci.starter.web.constant.TokenKeyConstant;
|
import com.vci.starter.web.enumpck.ResultCodeEnum;
|
import com.vci.starter.web.pagemodel.BaseResult;
|
import com.vci.starter.web.pagemodel.SessionInfo;
|
import com.vci.starter.web.util.LangBaseUtil;
|
import com.vci.starter.web.util.VciBaseUtil;
|
import com.vci.starter.web.util.WebThreadLocalUtil;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.util.CollectionUtils;
|
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
|
import javax.servlet.ServletException;
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import java.lang.reflect.Method;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
/**
|
* 权限拦截器
|
* @author weidy
|
* @date 2019/11/7 2:32 PM
|
*/
|
public class VciSecurityInterceptor implements HandlerInterceptor {
|
|
/**
|
* 日志对象
|
*/
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
|
/**
|
* 引入配置
|
*/
|
@Autowired(required = false)
|
private SpringMVCConfig springMVCConfig;
|
|
/**
|
* 会话,权限,token的接口
|
*/
|
@Autowired(required = false)
|
private VciSessionForLoginI sessionForLoginI;
|
|
/**
|
* 执行拦截
|
* @param request 请求对象
|
* @param response 相应对象
|
* @param handler 处理器
|
* @return 是否成功,false表示失败,其他的拦截器将不会执行
|
* @throws ServletException
|
*/
|
@Override
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
throws Exception {
|
//从头中获取token,然后调用接口类,获取用户的信息,具体实现类可以是从redis里获取,也可以是通过其他的方式获取
|
//如果头里面没有用户的token,那说明没有登录,
|
String requestUri = request.getRequestURI();
|
String contextPath = request.getContextPath();
|
String url = requestUri.substring(contextPath.length());
|
String userToken = request.getHeader(TokenKeyConstant.USER_TOKEN_KEY);
|
if(StringUtils.isBlank(userToken)){
|
userToken = request.getParameter(TokenKeyConstant.USER_TOKEN_KEY);
|
}
|
if(!(handler instanceof HandlerMethod)){
|
return true;
|
}
|
|
boolean unCheckLogin = false;
|
if(handler instanceof HandlerMethod) {
|
HandlerMethod hm = (HandlerMethod)handler;
|
Method method = hm.getMethod();
|
//设置了不校验的会直接返回true
|
if (method.isAnnotationPresent(VciUnCheckRight.class)) {
|
unCheckLogin = true;
|
}
|
if (method.getDeclaringClass().isAnnotationPresent(VciUnCheckRight.class)) {
|
unCheckLogin = true;
|
}
|
}
|
if(url.endsWith(".md")){
|
unCheckLogin = true;
|
}
|
if(unCheckLogin){
|
//虽然不校验权限,但是如果token不为空,需要更新当前用户
|
SessionInfo sessionInfo = getSessionInfo(userToken);
|
|
return true;
|
}
|
//获取配置文件中,不校验权限的路径
|
List<String> unCheckUrls = new ArrayList<>();
|
if(springMVCConfig !=null && springMVCConfig.getUnCheckUrls() !=null){
|
unCheckUrls = springMVCConfig.getUnCheckUrls();
|
}
|
if(StringUtils.isBlank(userToken) && !unCheckUrls.contains(url)){
|
//说明是没有用户信息的,而且也必须要校验是否登录的情况
|
//firefox上传文件依然使用头里存放token
|
if(logger.isErrorEnabled()) {
|
logger.error("请求" + url + ",但是没有登录");
|
}
|
sendErrorMsg(response,"没有登录系统,请先登录",1);
|
return false;
|
//被踢下线由websocket直接提醒
|
}else{
|
SessionInfo sessionInfo = getSessionInfo(userToken);
|
if(sessionInfo == null){
|
//也是说明不存在,被踢下线时也获取不到session的信息了
|
if(logger.isErrorEnabled()) {
|
logger.error("token值非法,或过期,或者用户已经被踢下线," + userToken);
|
}
|
sendErrorMsg(response,"token值非法,或过期,或者用户已经被踢下线," + userToken,1);
|
return false;
|
}else{
|
if(!unCheckUrls.contains(url)){
|
if(sessionForLoginI == null){
|
//说明没办法校验
|
String msg = "请求路径"+ url +"没权限访问";
|
if(logger.isErrorEnabled()) {
|
logger.error(msg + userToken);
|
}
|
sendErrorMsg(response,msg,2);
|
return false;
|
}else{
|
String systemPrivateToken = request.getHeader(TokenKeyConstant.SYSTEM_PRIVATE_KEY);
|
try {
|
if (sessionForLoginI.checkRequestRights(request, systemPrivateToken, sessionInfo, handler)) {
|
updateRequestTime(url,userToken);
|
}else{
|
return false;
|
}
|
}catch (Throwable e){
|
String errorMsg = LangBaseUtil.getErrorMsg(e);
|
if(logger.isErrorEnabled()) {
|
logger.error("检查请求是否符合权限出现了错误," + errorMsg, e);
|
}
|
sendErrorMsg(response,errorMsg,1);
|
return false;
|
}
|
}
|
}else{
|
updateRequestTime(url,userToken);
|
}
|
}
|
}
|
return true;
|
}
|
|
private SessionInfo getSessionInfo(String userToken){
|
SessionInfo sessionInfo = null;
|
if(StringUtils.isNotBlank(userToken)){
|
try{
|
sessionInfo = sessionForLoginI.getSessionInfoByToken(userToken);
|
}catch (Throwable e){
|
logger.error("获取token出错",e);
|
}
|
if(sessionInfo!=null){
|
WebThreadLocalUtil.setCurrentUserSessionInfoInThread(sessionInfo);
|
WebThreadLocalUtil.setTokenInThread(TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS+sessionInfo.getToken());
|
}
|
}
|
return sessionInfo;
|
}
|
|
/**
|
* 返回错误信息
|
* @param response 相应对象
|
* @param errorMsg 错误信息
|
* @param innerErrorCode 内部错误,1表示没有登录,2表示没有权限
|
* @throws Exception
|
*/
|
private void sendErrorMsg(HttpServletResponse response, String errorMsg, int innerErrorCode) throws Exception{
|
BaseResult baseResult = BaseResult.fail(errorMsg);
|
if(innerErrorCode ==1) {
|
baseResult.setCode(ResultCodeEnum.UNAUTHORIZED.code);
|
}else if(innerErrorCode == 2){
|
baseResult.setCode(ResultCodeEnum.NOT_RIGHT.code);
|
}
|
response.setCharacterEncoding("UTF-8");
|
response.getWriter().write(VciBaseUtil.getJSONStringWithDateFormat(baseResult));
|
}
|
|
/**
|
* 更新最后请求时间
|
* @param url 当前请求的路径
|
* @param userToken 用户的token
|
*/
|
private void updateRequestTime(String url,String userToken){
|
//记录最后访问的时间
|
List<String> unStorageRequestTimeUrls = new ArrayList<>();
|
if(springMVCConfig !=null && springMVCConfig.getUnStorageRequestTimeUrls() != null){
|
unStorageRequestTimeUrls = springMVCConfig.getUnStorageRequestTimeUrls();
|
}
|
if(CollectionUtils.isEmpty(unStorageRequestTimeUrls)){
|
unStorageRequestTimeUrls.add("smSessionController/checkIdleTime");
|
}
|
String url1 = url;
|
while(url1.startsWith("/")){
|
url1 = url1.substring(1);
|
}
|
if(sessionForLoginI != null && !unStorageRequestTimeUrls.contains(url1)){
|
sessionForLoginI.updateRequestTime(userToken);
|
}
|
}
|
}
|