Procházet zdrojové kódy

Merge remote-tracking branch 'origin/master'

lideyin před 6 roky
rodič
revize
815f619143

+ 4 - 6
examcloud-exchange-base/pom.xml

@@ -1,5 +1,8 @@
 <?xml version="1.0"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<project
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 	<modelVersion>4.0.0</modelVersion>
 	<parent>
 		<groupId>cn.com.qmth.examcloud.exchange</groupId>
@@ -20,11 +23,6 @@
 			<version>${examcloud.version}</version>
 		</dependency>
 
-		<dependency>
-			<groupId>com.upyun</groupId>
-			<artifactId>java-sdk</artifactId>
-			<version>4.0.1</version>
-		</dependency>
 		<dependency>
 			<groupId>com.aliyun</groupId>
 			<artifactId>aliyun-java-sdk-core</artifactId>

+ 5 - 0
examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/UpyunCloudServiceProvider.java

@@ -3,6 +3,7 @@ package cn.com.qmth.examcloud.exchange.inner.api.provider;
 import java.io.IOException;
 import java.util.Map;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -13,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.AES;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
 import cn.com.qmth.examcloud.exchange.inner.api.UpyunCloudService;
 import cn.com.qmth.examcloud.exchange.inner.api.request.DeleteFileReq;
 import cn.com.qmth.examcloud.exchange.inner.api.request.PutFileReq;
@@ -50,6 +52,9 @@ public class UpyunCloudServiceProvider extends ControllerSupport implements Upyu
 	public PutFileResp putFile(@ModelAttribute PutFileReq req) {
 		String fileSuffix = req.getFileSuffix();
 		String relativePath = req.getRelativePath();
+		if (StringUtils.isNotBlank(relativePath)) {
+			relativePath = PathUtil.startsWithoutSeparator(relativePath);
+		}
 		Map<String, String> properties = req.getProperties();
 		Long rootOrgId = req.getRootOrgId();
 		Long userId = req.getUserId();

+ 45 - 91
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/upyun/UpYunClient.java

@@ -4,14 +4,18 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
+import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
 import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.Base64;
+import java.util.Calendar;
 import java.util.Locale;
 import java.util.TimeZone;
 
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
 import org.apache.commons.compress.utils.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpStatus;
@@ -25,17 +29,14 @@ import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.util.EntityUtils;
 
-import com.upyun.UpException;
-import com.upyun.UpYunUtils;
-
 import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
 import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
-import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
+import cn.com.qmth.examcloud.commons.util.MD5;
 
 /**
- * upyun SDK定制版
+ * upyun client
  *
  * @author WANGWEI
  * @date 2018年11月21日
@@ -68,6 +69,8 @@ public class UpYunClient {
 
 	private final String METHOD_PUT = "PUT";
 
+	private final String METHOD_DELETE = "DELETE";
+
 	private final String DATE = "Date";
 
 	private final String AUTHORIZATION = "Authorization";
@@ -78,12 +81,6 @@ public class UpYunClient {
 
 	private RequestConfig requestConfig;
 
-	private String testUrl;
-
-	private String base64Auth = null;
-
-	private boolean unsafe;
-
 	private String domain;
 
 	/**
@@ -105,13 +102,7 @@ public class UpYunClient {
 		this.userName = userName;
 		this.password = password;
 		this.domain = domain;
-		this.md5Password = md5(password);
-
-		base64Auth = "Basic " + org.apache.commons.codec.binary.Base64
-				.encodeBase64String((userName + ":" + password).getBytes());
-		unsafe = false;
-
-		testUrl = PropertyHolder.getString("$upyun.testUrl");
+		this.md5Password = MD5.encrypt32(password);
 	}
 
 	/**
@@ -146,9 +137,6 @@ public class UpYunClient {
 	public UpYunPathInfo writeFile(String filePath, InputStream in) {
 		String path = formatPath(filePath);
 		String url = "https://" + API_DOMAIN + path;
-		if (filePath.endsWith(".test")) {
-			url = testUrl;
-		}
 
 		HttpPut httpPut = new HttpPut(url);
 		httpPut.setConfig(this.requestConfig);
@@ -157,16 +145,10 @@ public class UpYunClient {
 		long s = System.currentTimeMillis();
 		try {
 
-			String date = getGMTDate();
+			String date = getDate();
+			String authorization = sign(userName, md5Password, METHOD_PUT, path, date, "", "");
+			httpPut.addHeader(AUTHORIZATION, authorization);
 			httpPut.addHeader(DATE, date);
-
-			if (unsafe) {
-				httpPut.addHeader(AUTHORIZATION, base64Auth);
-			} else {
-				httpPut.addHeader(AUTHORIZATION, UpYunUtils
-						.sign(METHOD_PUT, date, path, userName, this.md5Password, null).trim());
-			}
-
 			httpPut.addHeader(MKDIR, "true");
 
 			httpPut.setEntity(new InputStreamEntity(in));
@@ -179,8 +161,6 @@ public class UpYunClient {
 			}
 		} catch (StatusException e) {
 			throw e;
-		} catch (UpException e) {
-			throw new ExamCloudRuntimeException(e);
 		} catch (Exception e) {
 			throw new ExamCloudRuntimeException(e);
 		} finally {
@@ -208,9 +188,6 @@ public class UpYunClient {
 	public void deleteFile(String filePath) {
 		String path = formatPath(filePath);
 		String url = "https://" + API_DOMAIN + path;
-		if (filePath.endsWith(".test")) {
-			url = testUrl;
-		}
 
 		HttpDelete httpDelete = new HttpDelete(url);
 		httpDelete.setConfig(this.requestConfig);
@@ -218,17 +195,11 @@ public class UpYunClient {
 
 		long s = System.currentTimeMillis();
 		try {
-
-			String date = getGMTDate();
+			String date = getDate();
+			String authorization = sign(userName, md5Password, METHOD_DELETE, path, date, "", "");
+			httpDelete.addHeader(AUTHORIZATION, authorization);
 			httpDelete.addHeader(DATE, date);
 
-			if (unsafe) {
-				httpDelete.addHeader(AUTHORIZATION, base64Auth);
-			} else {
-				httpDelete.addHeader(AUTHORIZATION, UpYunUtils
-						.sign(METHOD_PUT, date, path, userName, this.md5Password, null).trim());
-			}
-
 			response = httpclient.execute(httpDelete);
 			int statusCode = response.getStatusLine().getStatusCode();
 
@@ -238,8 +209,6 @@ public class UpYunClient {
 			}
 		} catch (StatusException e) {
 			throw e;
-		} catch (UpException e) {
-			throw new ExamCloudRuntimeException(e);
 		} catch (Exception e) {
 			throw new ExamCloudRuntimeException(e);
 		} finally {
@@ -255,7 +224,7 @@ public class UpYunClient {
 	}
 
 	/**
-	 * 格式化路径参数,去除前后的空格并确保以"/"开头,最后添加"/空间名"
+	 * 格式化路径参数
 	 * <p>
 	 * 最终构成的格式:"/空间名/文件路径"
 	 *
@@ -279,50 +248,35 @@ public class UpYunClient {
 		return SEPARATOR + bucketName + path;
 	}
 
-	/**
-	 * 对字符串进行 MD5 加密
-	 *
-	 * @param str
-	 *            待加密字符串
-	 * @return 加密后字符串
-	 */
-	private static String md5(String str) {
-		char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
-				'e', 'f'};
-		MessageDigest md5 = null;
-		try {
-			md5 = MessageDigest.getInstance("MD5");
-			md5.update(str.getBytes("UTF-8"));
-		} catch (NoSuchAlgorithmException e) {
-			e.printStackTrace();
-			throw new RuntimeException(e.getMessage());
-		} catch (UnsupportedEncodingException e) {
-			e.printStackTrace();
-			throw new RuntimeException(e.getMessage());
-		}
-		byte[] encodedValue = md5.digest();
-		int j = encodedValue.length;
-		char finalValue[] = new char[j * 2];
-		int k = 0;
-		for (int i = 0; i < j; i++) {
-			byte encoded = encodedValue[i];
-			finalValue[k++] = hexDigits[encoded >> 4 & 0xf];
-			finalValue[k++] = hexDigits[encoded & 0xf];
-		}
+	private String getDate() {
+		Calendar calendar = Calendar.getInstance();
+		SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",
+				Locale.US);
+		dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+		return dateFormat.format(calendar.getTime());
+	}
 
-		return new String(finalValue);
+	private byte[] hashHmac(String data, String key)
+			throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
+		SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
+		Mac mac = Mac.getInstance("HmacSHA1");
+		mac.init(signingKey);
+		return mac.doFinal(data.getBytes());
 	}
 
-	/**
-	 * 获取 GMT 格式时间戳
-	 *
-	 * @return GMT 格式时间戳
-	 */
-	private String getGMTDate() {
-		SimpleDateFormat formater = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'",
-				Locale.US);
-		formater.setTimeZone(TimeZone.getTimeZone("GMT"));
-		return formater.format(new Date());
+	private String sign(String key, String secret, String method, String uri, String date,
+			String policy, String md5) throws Exception {
+		String value = method + "&" + uri + "&" + date;
+		if (policy != null && policy.length() > 0) {
+			value = value + "&" + policy;
+		}
+
+		if (md5 != null && md5.length() > 0) {
+			value = value + "&" + md5;
+		}
+		byte[] hmac = hashHmac(value, secret);
+		String sign = Base64.getEncoder().encodeToString(hmac);
+		return "UPYUN " + key + ":" + sign;
 	}
 
 }

+ 35 - 19
examcloud-exchange-starter/src/main/java/cn/com/qmth/examcloud/exchange/config/EnterpriseAccessInterceptor.java

@@ -33,12 +33,14 @@ import cn.com.qmth.examcloud.web.support.StatusResponse;
  */
 public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 
-	private static final ExamCloudLog LOG = ExamCloudLogFactory.getLog(EnterpriseAccessInterceptor.class);
+	private static final ExamCloudLog LOG = ExamCloudLogFactory
+			.getLog(EnterpriseAccessInterceptor.class);
 
 	/**
 	 * 接口日志
 	 */
-	protected static final ExamCloudLog INTERFACE_LOG = ExamCloudLogFactory.getLog("INTERFACE_LOGGER");
+	protected static final ExamCloudLog INTERFACE_LOG = ExamCloudLogFactory
+			.getLog("INTERFACE_LOGGER");
 
 	/**
 	 * redis client
@@ -53,22 +55,27 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 	 * @param redisClient
 	 * @param commonCloudService
 	 */
-	public EnterpriseAccessInterceptor(RedisClient redisClient, CommonCloudService commonCloudService) {
+	public EnterpriseAccessInterceptor(RedisClient redisClient,
+			CommonCloudService commonCloudService) {
 		super();
 		this.redisClient = redisClient;
 		this.commonCloudService = commonCloudService;
 	}
 
 	@Override
-	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
-			throws Exception {
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
+			Object handler) throws Exception {
 		LOG.debug("preHandle... ...");
 
-		ApiInfo apiInfo = (ApiInfo) request.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
+		ApiInfo apiInfo = (ApiInfo) request
+				.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
 
-		Class<?> ctrClass = apiInfo.getBeanType();
-
-		if (!EnterpriseService.class.isAssignableFrom(ctrClass)) {
+		if (null != apiInfo) {
+			Class<?> ctrClass = apiInfo.getBeanType();
+			if (!EnterpriseService.class.isAssignableFrom(ctrClass)) {
+				return true;
+			}
+		} else {
 			return true;
 		}
 
@@ -79,7 +86,8 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 		if (StringUtils.isBlank(appId)) {
 			// 403
 			response.setStatus(HttpStatus.FORBIDDEN.value());
-			ServletUtil.returnJson(new StatusResponse("403", "'App-Id'('appId') is blank"), response);
+			ServletUtil.returnJson(new StatusResponse("403", "'App-Id'('appId') is blank"),
+					response);
 			return false;
 		}
 
@@ -90,7 +98,8 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 		if (StringUtils.isBlank(rootOrgId)) {
 			// 403
 			response.setStatus(HttpStatus.FORBIDDEN.value());
-			ServletUtil.returnJson(new StatusResponse("403", "'Root-Org-Id'('rootOrgId') is blank"), response);
+			ServletUtil.returnJson(new StatusResponse("403", "'Root-Org-Id'('rootOrgId') is blank"),
+					response);
 			return false;
 		}
 		Long rootOrgIdLong = null;
@@ -99,7 +108,9 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 		} catch (Exception e) {
 			// 403
 			response.setStatus(HttpStatus.FORBIDDEN.value());
-			ServletUtil.returnJson(new StatusResponse("403", "'Root-Org-Id'('rootOrgId') must be a long"), response);
+			ServletUtil.returnJson(
+					new StatusResponse("403", "'Root-Org-Id'('rootOrgId') must be a long"),
+					response);
 			return false;
 		}
 
@@ -110,7 +121,8 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 		if (StringUtils.isBlank(accessToken)) {
 			// 403
 			response.setStatus(HttpStatus.FORBIDDEN.value());
-			ServletUtil.returnJson(new StatusResponse("403", "'Access-Token'('access_token') is blank"), response);
+			ServletUtil.returnJson(
+					new StatusResponse("403", "'Access-Token'('access_token') is blank"), response);
 			return false;
 		}
 
@@ -127,15 +139,18 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 		} catch (Exception e) {
 			// 403
 			response.setStatus(HttpStatus.FORBIDDEN.value());
-			ServletUtil.returnJson(new StatusResponse("403", "'timestamp' must be a long"), response);
+			ServletUtil.returnJson(new StatusResponse("403", "'timestamp' must be a long"),
+					response);
 			return false;
 		}
 
-		request.setAttribute(HttpServletRequestAttribute.$_ENTERPRISE_ROOT_ORG_ID.name(), rootOrgIdLong);
+		request.setAttribute(HttpServletRequestAttribute.$_ENTERPRISE_ROOT_ORG_ID.name(),
+				rootOrgIdLong);
 
 		String key = "$_A_:" + rootOrgId + "_" + appId;
 
-		ThirdPartyAccessBean thirdPartyAccessBean = redisClient.get(key, ThirdPartyAccessBean.class);
+		ThirdPartyAccessBean thirdPartyAccessBean = redisClient.get(key,
+				ThirdPartyAccessBean.class);
 
 		if (null == thirdPartyAccessBean) {
 			thirdPartyAccessBean = getThirdPartyAccessInfo(rootOrgIdLong, appId);
@@ -160,7 +175,8 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 		if (!hexAscii.equalsIgnoreCase(accessToken)) {
 			// 403
 			response.setStatus(HttpStatus.FORBIDDEN.value());
-			ServletUtil.returnJson(new StatusResponse("403", "'Access-Token'('access_token') is wrong"), response);
+			ServletUtil.returnJson(
+					new StatusResponse("403", "'Access-Token'('access_token') is wrong"), response);
 			return false;
 		}
 
@@ -184,8 +200,8 @@ public final class EnterpriseAccessInterceptor implements HandlerInterceptor {
 	}
 
 	@Override
-	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
-			throws Exception {
+	public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
+			Object handler, Exception ex) throws Exception {
 		LOG.debug("afterCompletion... ...");
 	}