oss服务端签名客户端上传并设置服务端回调,服务端对回调进行验证
程序员文章站
2022-07-14 22:01:35
...
我的项目是使用的springboot,将官网的项目部分代码复制进来后测试,发现获取ossCallBody()这个方法获取不到值,遂,改造。代码如下。
package com.imiros.imiros.oss;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.tomcat.util.buf.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;
/**
* TODO
*
* @author <a href="[email protected]">hm</a>
* @version 1.0.0, 05-29-2019
*/
@RestController
@RequestMapping("oss")
@SuppressWarnings(value={"all"})
public class OssController {
static final Logger logger = LoggerFactory.getLogger(OssController.class);
static final String endpoint = "sts.cn-hangzhou.aliyuncs.com";
static final String accessKeyId = "";
static final String accessKeySecret = "";
static final String roleArn = "";
static final String roleSessionName = "";
//以上账号信息请使用自己的阿里云相关信息。
@RequestMapping("getToken")
public String getToken() {
JSONObject jsonObject = new JSONObject();
String policy = "{\n" +
" \"Version\": \"1\", \n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": [\n" +
" \"oss:*\"\n" +
" ], \n" +
" \"Resource\": [\n" +
" \"acs:oss:*:*:*\" \n" +
" ], \n" +
" \"Effect\": \"Allow\"\n" +
" }\n" +
" ]\n" +
"}";
try {
// 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
DefaultProfile.addEndpoint("", "", "Sts", endpoint);
// 构造default profile(参数留空,无需添加region ID)
IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
// 用profile构造client
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
request.setMethod(MethodType.POST);
request.setRoleArn(roleArn);
request.setRoleSessionName(roleSessionName);
// Optional
request.setPolicy(policy);
final AssumeRoleResponse response = client.getAcsResponse(request);
jsonObject.put("Expiration", response.getCredentials().getExpiration());
jsonObject.put("AccessKeyId", response.getCredentials().getAccessKeyId());
jsonObject.put("AccessKeySecret", response.getCredentials().getAccessKeySecret());
jsonObject.put("SecurityToken", response.getCredentials().getSecurityToken());
jsonObject.put("StatusCode", "200");
System.out.println(response.getCredentials());
} catch (ClientException e) {
jsonObject.put("ErrorCode", e.getErrCode());
jsonObject.put("StatusCode", "500");
jsonObject.put("ErrorMessage", e.getErrMsg());
}
logger.info("获取OSS的STS凭证响应信息 : " + jsonObject.toString());
return jsonObject.toString();
}
@RequestMapping(value = "callback")
public String upload(HttpServletRequest request, String filename) {
String ossCallbackBody = "";
JSONObject jsonObject = new JSONObject();
Map<String, String[]> map = request.getParameterMap();
if (map.size() != 0) {
for (String key : map.keySet()) {
ossCallbackBody += key + "=" + StringUtils.join(map.get(key)) + "&";
}
ossCallbackBody = ossCallbackBody.substring(0, ossCallbackBody.length() - 1);
}
logger.info("ossCallbackBody:" + ossCallbackBody);
boolean ret = VerifyOSSCallbackRequest(request, ossCallbackBody);
if (ret) {
jsonObject.put("filename", filename);
jsonObject.put("Status", "OK");
} else {
jsonObject.put("Status", "verify not ok");
}
logger.info("OSS的回调响应 :" + jsonObject.toString());
return jsonObject.toString();
}
protected boolean VerifyOSSCallbackRequest(HttpServletRequest request, String ossCallbackBody) {
boolean ret = false;
String autorizationInput = new String(request.getHeader("Authorization"));
String pubKeyInput = request.getHeader("x-oss-pub-key-url");
byte[] authorization = BinaryUtil.fromBase64String(autorizationInput);
byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput);
String pubKeyAddr = new String(pubKey);
if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/") && !pubKeyAddr
.startsWith("https://gosspublic.alicdn.com/")) {
System.out.println("pub key addr must be oss addrss");
return false;
}
String retString = executeGet(pubKeyAddr);
retString = retString.replace("-----BEGIN PUBLIC KEY-----", "");
retString = retString.replace("-----END PUBLIC KEY-----", "");
String queryString = request.getQueryString();
String uri = request.getRequestURI();
String decodeUri = null;
try {
decodeUri = java.net.URLDecoder.decode(uri, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String authStr = decodeUri;
if (queryString != null && !queryString.equals("")) {
authStr += "?" + queryString;
}
authStr += "\n" + ossCallbackBody;
ret = doCheck(authStr, authorization, retString);
logger.info("------authStr:" + authStr);
logger.info("------pubKeyAddr:" + pubKeyAddr);
logger.info("------authorization:" + authorization);
logger.info("------retString:" + retString);
return ret;
}
public String executeGet(String url) {
BufferedReader in = null;
String content = null;
try {
// 定义HttpClient
@SuppressWarnings("resource")
DefaultHttpClient client = new DefaultHttpClient();
// 实例化HTTP方法
HttpGet request = new HttpGet();
request.setURI(new URI(url));
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
content = sb.toString();
} catch (Exception e) {
} finally {
if (in != null) {
try {
in.close();// 最后要关闭BufferedReader
} catch (Exception e) {
e.printStackTrace();
}
}
return content;
}
}
public static boolean doCheck(String content, byte[] sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = BinaryUtil.fromBase64String(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes());
boolean bverify = signature.verify(sign);
return bverify;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
需要的pom文件如下:(我用的是java11,看下面的注释,java11缺少的那部分包可以不需要导入。在java8中都是有的,不需要再依赖了)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-sts</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.5.0</version>
</dependency>
<!-- 用java11接ossjdk缺少的包-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
注意:敲黑板啊,要测试回调必须把服务布到公网上。敲黑板啊,要测试回调必须把服务布到公网上。敲黑板啊,要测试回调必须把服务布到公网上。