package com.lean56.andplug.image.qiniu; import android.text.TextUtils; import android.util.Base64; import com.alibaba.fastjson.JSON; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.Charset; import java.security.GeneralSecurityException; public final class Auth { private final static Charset UTF_8 = Charset.forName("UTF-8"); /** * 上传策略,参数规格详见 * <p/> * http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html */ private static final String[] policyFields = new String[]{ "callbackUrl", "callbackBody", "callbackHost", "callbackBodyType", "callbackFetchKey", "returnUrl", "returnBody", "endUser", "saveKey", "insertOnly", "detectMime", "mimeLimit", "fsizeLimit", "fsizeMin", "persistentOps", "persistentNotifyUrl", "persistentPipeline", }; private static final String[] deprecatedPolicyFields = new String[]{ "asyncOps", }; private final String accessKey; private final SecretKeySpec secretKey; private Auth(String accessKey, SecretKeySpec secretKeySpec) { this.accessKey = accessKey; this.secretKey = secretKeySpec; } public static Auth create(String accessKey, String secretKey) { if (TextUtils.isEmpty(accessKey) || TextUtils.isEmpty(secretKey)) { throw new IllegalArgumentException("empty key"); } byte[] sk = secretKey.getBytes(UTF_8); SecretKeySpec secretKeySpec = new SecretKeySpec(sk, "HmacSHA1"); return new Auth(accessKey, secretKeySpec); } private static void copyPolicy(final StringMap policy, StringMap originPolicy, final boolean strict) { if (originPolicy == null) { return; } originPolicy.forEach(new StringMap.Consumer() { @Override public void accept(String key, Object value) { if (inStringArray(key, deprecatedPolicyFields)) { throw new IllegalArgumentException(key + " is deprecated!"); } if (!strict || inStringArray(key, policyFields)) { policy.put(key, value); } } }); } private static boolean inStringArray(String s, String[] array) { for (String x : array) { if (x.equals(s)) { return true; } } return false; } private Mac createMac() { Mac mac; try { mac = Mac.getInstance("HmacSHA1"); mac.init(secretKey); } catch (GeneralSecurityException e) { e.printStackTrace(); throw new IllegalArgumentException(e); } return mac; } public String sign(byte[] data) { Mac mac = createMac(); String encodedSign = Base64.encodeToString(mac.doFinal(data), Base64.URL_SAFE | Base64.NO_WRAP); return this.accessKey + ":" + encodedSign; } public String sign(String data) { return sign(data.getBytes(UTF_8)); } public String signWithData(byte[] data) { String s = Base64.encodeToString(data, Base64.URL_SAFE | Base64.NO_WRAP); return sign(s.getBytes(UTF_8)) + ":" + s; } public String signWithData(String data) { return signWithData(data.getBytes(UTF_8)); } /** * scope = bucket * 一般情况下可通过此方法获取token * * @param bucket 空间名 * @return 生成的上传token */ public String uploadToken(String bucket) { return uploadToken(bucket, null, 3600, null, true); } /** * scope = bucket:key * 同名文件覆盖操作、只能上传指定key的文件可以可通过此方法获取token * * @param bucket 空间名 * @param key key,可为 null * @return 生成的上传token */ public String uploadToken(String bucket, String key) { return uploadToken(bucket, key, 3600, null, true); } /** * 生成上传token * * @param bucket 空间名 * @param key key,可为 null * @param expires 有效时长,单位秒 * @param policy 上传策略的其它参数,如 new StringMap().put("endUser", "uid").putNotEmpty("returnBody", "")。 * scope通过 bucket、key间接设置,deadline 通过 expires 间接设置 * @return 生成的上传token */ public String uploadToken(String bucket, String key, long expires, StringMap policy) { return uploadToken(bucket, key, expires, policy, true); } /** * 生成上传token * * @param bucket 空间名 * @param key key,可为 null * @param expires 有效时长,单位秒。默认3600s * @param policy 上传策略的其它参数,如 new StringMap().put("endUser", "uid").putNotEmpty("returnBody", "")。 * scope通过 bucket、key间接设置,deadline 通过 expires 间接设置 * @param strict 是否去除非限定的策略字段,默认true * @return 生成的上传token */ public String uploadToken(String bucket, String key, long expires, StringMap policy, boolean strict) { long deadline = System.currentTimeMillis() / 1000 + expires; return uploadTokenWithDeadline(bucket, key, deadline, policy, strict); } String uploadTokenWithDeadline(String bucket, String key, long deadline, StringMap policy, boolean strict) { String scope = bucket; if (key != null) { scope = bucket + ":" + key; } StringMap x = new StringMap(); copyPolicy(x, policy, strict); x.put("scope", scope); x.put("deadline", deadline); String s = JSON.toJSONString(x.map()); return signWithData(s.getBytes(UTF_8)); } }