|
|
|
@ -1,6 +1,5 @@
|
|
|
|
|
package com.anjiplus.template.gaea.business.filter;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.anji.plus.gaea.bean.ResponseBean;
|
|
|
|
|
import com.anji.plus.gaea.cache.CacheHelper;
|
|
|
|
@ -16,7 +15,6 @@ import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
import org.springframework.core.annotation.Order;
|
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
import org.springframework.util.AntPathMatcher;
|
|
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
|
|
|
|
import javax.servlet.*;
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
@ -24,9 +22,9 @@ import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static com.anji.plus.gaea.constant.GaeaConstant.URL_REPLACEMENT;
|
|
|
|
|
|
|
|
|
@ -39,23 +37,23 @@ import static com.anji.plus.gaea.constant.GaeaConstant.URL_REPLACEMENT;
|
|
|
|
|
@Order(Integer.MIN_VALUE + 99)
|
|
|
|
|
public class TokenFilter implements Filter {
|
|
|
|
|
private static final Pattern PATTERN = Pattern.compile(".*().*");
|
|
|
|
|
private static final String USER_GUEST = "guest";
|
|
|
|
|
|
|
|
|
|
@Value("${server.servlet.context-path:'/'}")
|
|
|
|
|
@Value("${server.servlet.context-path:/}")
|
|
|
|
|
private String SLASH = "/";
|
|
|
|
|
private AntPathMatcher antPathMatcher = new AntPathMatcher();
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private CacheHelper cacheHelper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private JwtBean jwtBean;
|
|
|
|
|
|
|
|
|
|
/** 跳过token验证和权限验证的url清单*/
|
|
|
|
|
@Value("#{'${customer.skip-authenticate-urls}'.split(',')}")
|
|
|
|
|
/**
|
|
|
|
|
* 跳过token验证和权限验证的url清单
|
|
|
|
|
*/
|
|
|
|
|
@Value("#{'${customer.skip-authenticate-urls:}'.split(',')}")
|
|
|
|
|
private List<String> skipAuthenticateUrls;
|
|
|
|
|
private Pattern skipAuthenticatePattern;
|
|
|
|
|
|
|
|
|
|
private AntPathMatcher antPathMatcher = new AntPathMatcher();
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void init(FilterConfig filterConfig) throws ServletException {
|
|
|
|
|
// 生成匹配正则,跳过token验证和权限验证的url
|
|
|
|
@ -69,13 +67,25 @@ public class TokenFilter implements Filter {
|
|
|
|
|
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
|
|
|
|
String uri = request.getRequestURI();
|
|
|
|
|
|
|
|
|
|
// TODO 暂时先不校验 直接放行
|
|
|
|
|
/*if (true) {
|
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
|
return;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
//OPTIONS直接放行
|
|
|
|
|
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SLASH.equals(uri) || SLASH.concat("/").equals(uri)) {
|
|
|
|
|
// swagger相关的直接放行
|
|
|
|
|
if (uri.contains("swagger-ui") || uri.contains("swagger-resources")) {
|
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SLASH.equals(uri) || SLASH.concat(BusinessConstant.SLASH).equals(uri)) {
|
|
|
|
|
response.sendRedirect(SLASH + "/index.html");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -125,51 +135,19 @@ public class TokenFilter implements Filter {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
String gaeaUserJsonStr = cacheHelper.stringGet(userKey);
|
|
|
|
|
// 延长有效期
|
|
|
|
|
cacheHelper.stringSetExpire(tokenKey, token, 3600);
|
|
|
|
|
cacheHelper.stringSetExpire(userKey, gaeaUserJsonStr, 3600);
|
|
|
|
|
|
|
|
|
|
//判断接口权限
|
|
|
|
|
//请求路径
|
|
|
|
|
//String requestUrl = request.getRequestURI(); requestUrl中可能会有contextpath,而底层扫描的controller是没有的
|
|
|
|
|
String servletPath = request.getServletPath();
|
|
|
|
|
String methodValue = request.getMethod();
|
|
|
|
|
//请求方法+#+请求路径
|
|
|
|
|
String urlKey = methodValue + GaeaConstant.URL_SPLIT + servletPath;
|
|
|
|
|
|
|
|
|
|
GaeaUserDto gaeaUserDto = JSONObject.parseObject(gaeaUserJsonStr, GaeaUserDto.class);
|
|
|
|
|
List<String> authorities = gaeaUserDto.getAuthorities();
|
|
|
|
|
Map<String, String> applicationNameAllAuthorities = cacheHelper.hashGet(BusinessConstant.GAEA_SECURITY_AUTHORITIES);
|
|
|
|
|
AtomicBoolean authFlag = new AtomicBoolean(false);
|
|
|
|
|
//查询当前请求是否在对应的权限里。即:先精确匹配(保证当前路由是需要精确匹配还是模糊匹配,防止精确匹配的被模糊匹配)
|
|
|
|
|
// 比如:/user/info和/user/**同时存在,/user/info,被/user/**匹配掉
|
|
|
|
|
if (applicationNameAllAuthorities.containsKey(urlKey)) {
|
|
|
|
|
String permissionCode = applicationNameAllAuthorities.get(urlKey);
|
|
|
|
|
if (authorities.contains(permissionCode)) {
|
|
|
|
|
authFlag.set(true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
List<String> collect = applicationNameAllAuthorities.keySet().stream()
|
|
|
|
|
.filter(key -> StringUtils.isNotBlank(key) && key.contains(URL_REPLACEMENT))
|
|
|
|
|
.filter(key -> antPathMatcher.match(key, urlKey)).collect(Collectors.toList());
|
|
|
|
|
if (CollectionUtils.isEmpty(collect)) {
|
|
|
|
|
authFlag.set(true);
|
|
|
|
|
}else {
|
|
|
|
|
collect.forEach(key -> {
|
|
|
|
|
String permissionCode = applicationNameAllAuthorities.getOrDefault(key, "");
|
|
|
|
|
if (authorities.contains(permissionCode)) {
|
|
|
|
|
authFlag.set(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// 判断用户是否有该url的权限
|
|
|
|
|
if (!BusinessConstant.USER_ADMIN.equals(loginName)) {
|
|
|
|
|
AtomicBoolean authorizeFlag = authorize(request, gaeaUserJsonStr);
|
|
|
|
|
if (!authorizeFlag.get()) {
|
|
|
|
|
authError(response);//无权限
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!authFlag.get()) {
|
|
|
|
|
//无权限
|
|
|
|
|
authError(response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 延长有效期
|
|
|
|
|
cacheHelper.stringSetExpire(tokenKey, token, 3600);
|
|
|
|
|
cacheHelper.stringSetExpire(userKey, gaeaUserJsonStr, 3600);
|
|
|
|
|
|
|
|
|
|
//执行
|
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
@ -205,14 +183,58 @@ public class TokenFilter implements Filter {
|
|
|
|
|
return Pattern.compile(patternString.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断用户是否有该接口的权限
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private AtomicBoolean authorize(HttpServletRequest request, String gaeaUserJsonStr){
|
|
|
|
|
|
|
|
|
|
//判断接口权限
|
|
|
|
|
//请求路径
|
|
|
|
|
String requestUrl = request.getRequestURI();
|
|
|
|
|
if (!BusinessConstant.SLASH.equals(SLASH)) {
|
|
|
|
|
requestUrl = requestUrl.substring(SLASH.length());
|
|
|
|
|
}
|
|
|
|
|
String methodValue = request.getMethod();
|
|
|
|
|
//请求方法+#+请求路径
|
|
|
|
|
String path = methodValue + GaeaConstant.URL_SPLIT + requestUrl;
|
|
|
|
|
|
|
|
|
|
GaeaUserDto gaeaUserDto = JSONObject.parseObject(gaeaUserJsonStr, GaeaUserDto.class);
|
|
|
|
|
List<String> userAuthorities = gaeaUserDto.getAuthorities();
|
|
|
|
|
Map<String, String> authoritiesAllMap = cacheHelper.hashGet(BusinessConstant.GAEA_SECURITY_AUTHORITIES);
|
|
|
|
|
|
|
|
|
|
AtomicBoolean authFlag = new AtomicBoolean(false);
|
|
|
|
|
|
|
|
|
|
// 接口GET#/gaeaDictItem/pageList
|
|
|
|
|
if(authoritiesAllMap.containsKey(path)){
|
|
|
|
|
String permissionCode = authoritiesAllMap.get(path);
|
|
|
|
|
boolean flag = userAuthorities.contains(permissionCode);
|
|
|
|
|
authFlag.set(flag);
|
|
|
|
|
return authFlag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 接口GET#/accessUser/roleTree/**
|
|
|
|
|
Optional<String> optionalMatchKey = authoritiesAllMap.keySet().stream()
|
|
|
|
|
.filter(key -> StringUtils.isNotBlank(key) && key.contains(URL_REPLACEMENT))
|
|
|
|
|
.filter(key -> antPathMatcher.match(key, path)).findFirst();
|
|
|
|
|
if(optionalMatchKey.isPresent() == false){
|
|
|
|
|
authFlag.set(true);
|
|
|
|
|
return authFlag;
|
|
|
|
|
}
|
|
|
|
|
String authoritieKey = optionalMatchKey.get();
|
|
|
|
|
String needPermission = authoritiesAllMap.get(authoritieKey);
|
|
|
|
|
boolean flag = userAuthorities.contains(needPermission);
|
|
|
|
|
authFlag.set(flag);
|
|
|
|
|
return authFlag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void error(HttpServletResponse response) throws IOException {
|
|
|
|
|
ResponseBean responseBean = ResponseBean.builder().code("50014").message("The Token has expired").build();
|
|
|
|
|
ResponseBean responseBean = ResponseBean.builder().code("50008").message("The Token has expired").build();
|
|
|
|
|
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
|
|
|
|
|
response.getWriter().print(JSONObject.toJSONString(responseBean));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void authError(HttpServletResponse response) throws IOException {
|
|
|
|
|
ResponseBean responseBean = ResponseBean.builder().code("User.no.authority").message("没有权限").build();
|
|
|
|
|
ResponseBean responseBean = ResponseBean.builder().code("User.no.authority").message("no auth").build();
|
|
|
|
|
response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
|
|
|
|
|
response.getWriter().print(JSONObject.toJSONString(responseBean));
|
|
|
|
|
}
|
|
|
|
|