|
@@ -1,32 +1,22 @@
|
|
package cn.com.qmth.examcloud.web.security;
|
|
package cn.com.qmth.examcloud.web.security;
|
|
|
|
|
|
-import java.io.File;
|
|
|
|
-import java.io.IOException;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Set;
|
|
|
|
-
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
-import org.apache.commons.collections.CollectionUtils;
|
|
|
|
-import org.apache.commons.io.FileUtils;
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
-import org.slf4j.MDC;
|
|
|
|
|
|
+import org.apache.logging.log4j.ThreadContext;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.web.servlet.HandlerInterceptor;
|
|
import org.springframework.web.servlet.HandlerInterceptor;
|
|
import org.springframework.web.servlet.ModelAndView;
|
|
import org.springframework.web.servlet.ModelAndView;
|
|
|
|
|
|
-import com.google.common.collect.Sets;
|
|
|
|
-
|
|
|
|
import cn.com.qmth.examcloud.api.commons.CloudService;
|
|
import cn.com.qmth.examcloud.api.commons.CloudService;
|
|
import cn.com.qmth.examcloud.api.commons.EnterpriseService;
|
|
import cn.com.qmth.examcloud.api.commons.EnterpriseService;
|
|
import cn.com.qmth.examcloud.api.commons.security.bean.User;
|
|
import cn.com.qmth.examcloud.api.commons.security.bean.User;
|
|
import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
|
|
import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
|
|
import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
|
|
import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
|
|
-import cn.com.qmth.examcloud.commons.util.JsonUtil;
|
|
|
|
-import cn.com.qmth.examcloud.commons.util.PathUtil;
|
|
|
|
-import cn.com.qmth.examcloud.commons.util.RegExpUtil;
|
|
|
|
|
|
+import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
|
|
import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
|
+import cn.com.qmth.examcloud.web.support.ApiInfo;
|
|
import cn.com.qmth.examcloud.web.support.ServletUtil;
|
|
import cn.com.qmth.examcloud.web.support.ServletUtil;
|
|
import cn.com.qmth.examcloud.web.support.StatusResponse;
|
|
import cn.com.qmth.examcloud.web.support.StatusResponse;
|
|
|
|
|
|
@@ -42,40 +32,13 @@ public abstract class RequestPermissionInterceptor implements HandlerInterceptor
|
|
private static final ExamCloudLog LOG = ExamCloudLogFactory
|
|
private static final ExamCloudLog LOG = ExamCloudLogFactory
|
|
.getLog(RequestPermissionInterceptor.class);
|
|
.getLog(RequestPermissionInterceptor.class);
|
|
|
|
|
|
- /**
|
|
|
|
- * 接口日志
|
|
|
|
- */
|
|
|
|
protected static final ExamCloudLog INTERFACE_LOG = ExamCloudLogFactory
|
|
protected static final ExamCloudLog INTERFACE_LOG = ExamCloudLogFactory
|
|
.getLog("INTERFACE_LOGGER");
|
|
.getLog("INTERFACE_LOGGER");
|
|
|
|
|
|
- private static final Set<String> RESOURCE_NAME_SET = Sets.newConcurrentHashSet();
|
|
|
|
|
|
+ private ResourceManager resourceManager;
|
|
|
|
|
|
- /**
|
|
|
|
- * redis client
|
|
|
|
- */
|
|
|
|
private RedisClient redisClient;
|
|
private RedisClient redisClient;
|
|
|
|
|
|
- /**
|
|
|
|
- * 例外请求前缀的正则表达式集合(不进行权限校验)
|
|
|
|
- */
|
|
|
|
- private Set<String> exclusions;
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 热加载配置文件
|
|
|
|
- *
|
|
|
|
- * @author WANGWEI
|
|
|
|
- * @param resourceName
|
|
|
|
- */
|
|
|
|
- public synchronized void configure(String resourceName) {
|
|
|
|
- if (RESOURCE_NAME_SET.contains(resourceName)) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- String path = PathUtil.getResoucePath(resourceName);
|
|
|
|
- loadFromFile(path);
|
|
|
|
-
|
|
|
|
- RESOURCE_NAME_SET.add(resourceName);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* 判断是否有请求权限
|
|
* 判断是否有请求权限
|
|
*
|
|
*
|
|
@@ -102,34 +65,17 @@ public abstract class RequestPermissionInterceptor implements HandlerInterceptor
|
|
Object handler) throws Exception {
|
|
Object handler) throws Exception {
|
|
LOG.debug("preHandle... ...");
|
|
LOG.debug("preHandle... ...");
|
|
|
|
|
|
- Class<?> ctrClass = (Class<?>) request.getAttribute("$ctrClass");
|
|
|
|
|
|
+ ApiInfo apiInfo = (ApiInfo) request
|
|
|
|
+ .getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
|
|
|
|
+
|
|
|
|
+ Class<?> ctrClass = apiInfo.getBeanType();
|
|
if (CloudService.class.isAssignableFrom(ctrClass)
|
|
if (CloudService.class.isAssignableFrom(ctrClass)
|
|
|| EnterpriseService.class.isAssignableFrom(ctrClass)) {
|
|
|| EnterpriseService.class.isAssignableFrom(ctrClass)) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- String mappingPath = (String) request.getAttribute("$mappingPath");
|
|
|
|
-
|
|
|
|
- if ("[runtime][][GET]".equals(mappingPath)) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (mappingPath.startsWith("[${server.error.path:${error.path:/error}}][]")) {
|
|
|
|
- response.setStatus(HttpStatus.NOT_FOUND.value());
|
|
|
|
- ServletUtil.returnJson(new StatusResponse("404", "not found."), response);
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (CollectionUtils.isNotEmpty(exclusions)) {
|
|
|
|
- for (String e : exclusions) {
|
|
|
|
- if (mappingPath.matches(e)) {
|
|
|
|
- if (INTERFACE_LOG.isDebugEnabled()) {
|
|
|
|
- INTERFACE_LOG.debug("No authentication. mapping=" + mappingPath);
|
|
|
|
- }
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ String mapping = (String) request
|
|
|
|
+ .getAttribute(HttpServletRequestAttribute.$_MAPPING.name());
|
|
|
|
|
|
String key = null;
|
|
String key = null;
|
|
String token = null;
|
|
String token = null;
|
|
@@ -150,6 +96,17 @@ public abstract class RequestPermissionInterceptor implements HandlerInterceptor
|
|
token = request.getParameter("$token");
|
|
token = request.getParameter("$token");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (StringUtils.isBlank(key) || StringUtils.isBlank(token)) {
|
|
|
|
+ boolean naked = resourceManager.isNaked(apiInfo, mapping);
|
|
|
|
+ if (naked) {
|
|
|
|
+ return true;
|
|
|
|
+ } else {
|
|
|
|
+ response.setStatus(HttpStatus.FORBIDDEN.value());
|
|
|
|
+ ServletUtil.returnJson(new StatusResponse("403", "unallowed"), response);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if (StringUtils.isBlank(key)) {
|
|
if (StringUtils.isBlank(key)) {
|
|
response.setStatus(HttpStatus.FORBIDDEN.value());
|
|
response.setStatus(HttpStatus.FORBIDDEN.value());
|
|
ServletUtil.returnJson(new StatusResponse("403", "key is blank."), response);
|
|
ServletUtil.returnJson(new StatusResponse("403", "key is blank."), response);
|
|
@@ -161,13 +118,7 @@ public abstract class RequestPermissionInterceptor implements HandlerInterceptor
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- Integer sessionTimeout = redisClient.get("$_SESSION_TIMEOUT", Integer.class);
|
|
|
|
- User user = null;
|
|
|
|
- if (null == sessionTimeout) {
|
|
|
|
- user = redisClient.get(key, User.class);
|
|
|
|
- } else {
|
|
|
|
- user = redisClient.get(key, User.class, sessionTimeout);
|
|
|
|
- }
|
|
|
|
|
|
+ User user = redisClient.get(key, User.class);
|
|
|
|
|
|
if (null == user) {
|
|
if (null == user) {
|
|
response.setStatus(HttpStatus.FORBIDDEN.value());
|
|
response.setStatus(HttpStatus.FORBIDDEN.value());
|
|
@@ -179,15 +130,17 @@ public abstract class RequestPermissionInterceptor implements HandlerInterceptor
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- MDC.put("KEY", key);
|
|
|
|
|
|
+ redisClient.expire(key, user.getSessionTimeout());
|
|
|
|
+
|
|
|
|
+ ThreadContext.put("CALLER", key);
|
|
|
|
|
|
- if (!hasPermission(mappingPath, user)) {
|
|
|
|
|
|
+ if (!resourceManager.hasPermission(user, apiInfo, mapping)) {
|
|
response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
|
|
response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
|
|
ServletUtil.returnJson(new StatusResponse("405", "no permission."), response);
|
|
ServletUtil.returnJson(new StatusResponse("405", "no permission."), response);
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- request.setAttribute("$accessUser", user);
|
|
|
|
|
|
+ request.setAttribute(HttpServletRequestAttribute.$_ACCESS_USER.name(), user);
|
|
request.setAttribute("$kt", key + ":" + token);
|
|
request.setAttribute("$kt", key + ":" + token);
|
|
|
|
|
|
return true;
|
|
return true;
|
|
@@ -205,32 +158,8 @@ public abstract class RequestPermissionInterceptor implements HandlerInterceptor
|
|
LOG.debug("afterCompletion... ...");
|
|
LOG.debug("afterCompletion... ...");
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * 加载配置项
|
|
|
|
- *
|
|
|
|
- * @author WANGWEI
|
|
|
|
- * @param path
|
|
|
|
- */
|
|
|
|
- private void loadFromFile(String path) {
|
|
|
|
- try {
|
|
|
|
- Set<String> newExclusions = Sets.newHashSet();
|
|
|
|
- List<String> lines = FileUtils.readLines(new File(path), "UTF-8");
|
|
|
|
- for (String cur : lines) {
|
|
|
|
- if (StringUtils.isNotBlank(cur)) {
|
|
|
|
- cur = cur.trim();
|
|
|
|
- if (cur.startsWith("regexp:")) {
|
|
|
|
- cur = StringUtils.replace(cur, "regexp:", "", 1);
|
|
|
|
- } else {
|
|
|
|
- cur = RegExpUtil.escape(cur);
|
|
|
|
- }
|
|
|
|
- newExclusions.add(cur.trim());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- exclusions = newExclusions;
|
|
|
|
- LOG.info("exclusions=" + JsonUtil.toJson(exclusions));
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- LOG.error("fail to load config from file. filePath=" + path, e);
|
|
|
|
- }
|
|
|
|
|
|
+ public void setResourceManager(ResourceManager resourceManager) {
|
|
|
|
+ this.resourceManager = resourceManager;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|