阿里云新版人脸识别基于JAVA签名校验使用示例教程

作者:俏巴


概述


阿里云会对每个访问的请求进行身份验证,所以无论使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。通过使用 Access Key ID 和 Access Key Secret 进行对称加密的方法来验证请求的发送者身份。阿里云提供了多种语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从这里了解更多阿里云 SDK 的信息,前面系列博客也结合各种语言的SDK进行了实现。本文以DetectFace API为示例,演示实际基于签名校验的实现。


操作步骤


1、pom.xml


   <dependencies>
    <span class="xml"><span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.httpcomponents<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>httpclient<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/commons-lang/commons-lang --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>commons-lang<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>commons-lang<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/log4j/log4j --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>log4j<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>log4j<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.2.17<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/com.google.collections/google-collections --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.google.collections<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>google-collections<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0-rc2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span></span></code></pre>

2、工具类:UrlUtil


import java.net.URLEncoder;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
public class UrlUtil {
private <span class="hljs-keyword">static</span> Logger logger = Logger.getLogger(UrlUtil.class);
private final <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> CHARSET_UTF8 = <span class="hljs-string">"utf8"</span>;
<span class="hljs-comment">/**
 *
 * @param url
 * @return
 */</span>
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> urlEncode(<span class="hljs-built_in">String</span> url) {
    <span class="hljs-keyword">if</span> (!StringUtils.isEmpty(url)) {
        <span class="hljs-keyword">try</span> {
            url = URLEncoder.encode(url, <span class="hljs-string">"UTF-8"</span>);
        } <span class="hljs-keyword">catch</span> (Exception e) {
            logger.warn(<span class="hljs-string">"Url encode error:"</span> + e.getMessage());
        }
    }
    <span class="hljs-keyword">return</span> url;
}
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> generateQueryString(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; params, boolean isEncodeKV) {
    StringBuilder canonicalizedQueryString = <span class="hljs-keyword">new</span> StringBuilder();
    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">Map</span>.Entry&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; entry : params.entrySet()) {
        <span class="hljs-keyword">if</span> (isEncodeKV)
            canonicalizedQueryString.append(percentEncode(entry.getKey())).append(<span class="hljs-string">"="</span>)
                    .append(percentEncode(entry.getValue())).append(<span class="hljs-string">"&amp;"</span>);
        <span class="hljs-keyword">else</span>
            canonicalizedQueryString.append(entry.getKey()).append(<span class="hljs-string">"="</span>)
                    .append(entry.getValue()).append(<span class="hljs-string">"&amp;"</span>);
    }
    <span class="hljs-keyword">if</span> (canonicalizedQueryString.length() &gt; <span class="hljs-number">1</span>) {
        canonicalizedQueryString.setLength(canonicalizedQueryString.length() - <span class="hljs-number">1</span>);
    }
    <span class="hljs-keyword">return</span> canonicalizedQueryString.toString();
}
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> percentEncode(<span class="hljs-built_in">String</span> value) {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 使用URLEncoder.encode编码后,将"+","*","%7E"做替换即满足 API规定的编码规范</span>
        <span class="hljs-keyword">return</span> value == <span class="hljs-literal">null</span> ? <span class="hljs-literal">null</span> : URLEncoder.encode(value, CHARSET_UTF8)
                .replace(<span class="hljs-string">"+"</span>, <span class="hljs-string">"%20"</span>).replace(<span class="hljs-string">"*"</span>, <span class="hljs-string">"%2A"</span>).replace(<span class="hljs-string">"%7E"</span>, <span class="hljs-string">"~"</span>);
    } <span class="hljs-keyword">catch</span> (Exception e) {
        <span class="hljs-comment">//不可能发生的异常</span>
    }
    <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
}

}


3、工具类:SignatureUtils


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
public class SignatureUtils {
private final <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> CHARSET_UTF8 = <span class="hljs-string">"utf8"</span>;
private final <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> ALGORITHM = <span class="hljs-string">"UTF-8"</span>;
private final <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> SEPARATOR = <span class="hljs-string">"&amp;"</span>;
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; splitQueryString(<span class="hljs-built_in">String</span> url)
        throws URISyntaxException, UnsupportedEncodingException {
    URI uri = <span class="hljs-keyword">new</span> URI(url);
    <span class="hljs-built_in">String</span> query = uri.getQuery();
    final <span class="hljs-built_in">String</span>[] pairs = query.split(<span class="hljs-string">"&amp;"</span>);
    TreeMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; queryMap = <span class="hljs-keyword">new</span> TreeMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;();
    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">String</span> pair : pairs) {
        final int idx = pair.indexOf(<span class="hljs-string">"="</span>);
        final <span class="hljs-built_in">String</span> key = idx &gt; <span class="hljs-number">0</span> ? pair.substring(<span class="hljs-number">0</span>, idx) : pair;
        <span class="hljs-keyword">if</span> (!queryMap.containsKey(key)) {
            queryMap.put(key, URLDecoder.decode(pair.substring(idx + <span class="hljs-number">1</span>), CHARSET_UTF8));
        }
    }
    <span class="hljs-keyword">return</span> queryMap;
}
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> generate(<span class="hljs-built_in">String</span> method, <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; parameter,
                              <span class="hljs-built_in">String</span> accessKeySecret) throws Exception {
    <span class="hljs-built_in">String</span> signString = generateSignString(method, parameter);
    System.out.println(<span class="hljs-string">"signString---"</span>+signString);
    byte[] signBytes = hmacSHA1Signature(accessKeySecret + <span class="hljs-string">"&amp;"</span>, signString);
    <span class="hljs-built_in">String</span> signature = newStringByBase64(signBytes);
    System.out.println(<span class="hljs-string">"signature---"</span>+signature);
    <span class="hljs-keyword">if</span> (<span class="hljs-string">"POST"</span>.equals(method))
        <span class="hljs-keyword">return</span> signature;
    <span class="hljs-keyword">return</span> URLEncoder.encode(signature, <span class="hljs-string">"UTF-8"</span>);
}
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> generateSignString(<span class="hljs-built_in">String</span> httpMethod, <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; parameter)
        throws IOException {
    TreeMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; sortParameter = <span class="hljs-keyword">new</span> TreeMap&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt;();
    sortParameter.putAll(parameter);
    <span class="hljs-built_in">String</span> canonicalizedQueryString = UrlUtil.generateQueryString(sortParameter, <span class="hljs-literal">true</span>);
    <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> == httpMethod) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"httpMethod can not be empty"</span>);
    }
    StringBuilder stringToSign = <span class="hljs-keyword">new</span> StringBuilder();
    stringToSign.append(httpMethod).append(SEPARATOR);
    stringToSign.append(percentEncode(<span class="hljs-string">"/"</span>)).append(SEPARATOR);
    stringToSign.append(percentEncode(canonicalizedQueryString));
    <span class="hljs-keyword">return</span> stringToSign.toString();
}
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> percentEncode(<span class="hljs-built_in">String</span> value) {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">return</span> value == <span class="hljs-literal">null</span> ? <span class="hljs-literal">null</span> : URLEncoder.encode(value, CHARSET_UTF8)
                .replace(<span class="hljs-string">"+"</span>, <span class="hljs-string">"%20"</span>).replace(<span class="hljs-string">"*"</span>, <span class="hljs-string">"%2A"</span>).replace(<span class="hljs-string">"%7E"</span>, <span class="hljs-string">"~"</span>);
    } <span class="hljs-keyword">catch</span> (Exception e) {
    }
    <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
}
public <span class="hljs-keyword">static</span> byte[] hmacSHA1Signature(<span class="hljs-built_in">String</span> secret, <span class="hljs-built_in">String</span> baseString)
        throws Exception {
    <span class="hljs-keyword">if</span> (StringUtils.isEmpty(secret)) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IOException(<span class="hljs-string">"secret can not be empty"</span>);
    }
    <span class="hljs-keyword">if</span> (StringUtils.isEmpty(baseString)) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
    Mac mac = Mac.getInstance(<span class="hljs-string">"HmacSHA1"</span>);
    SecretKeySpec keySpec = <span class="hljs-keyword">new</span> SecretKeySpec(secret.getBytes(CHARSET_UTF8), ALGORITHM);
    mac.init(keySpec);
    <span class="hljs-keyword">return</span> mac.doFinal(baseString.getBytes(CHARSET_UTF8));
}
public <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> newStringByBase64(byte[] bytes)
        throws UnsupportedEncodingException {
    <span class="hljs-keyword">if</span> (bytes == <span class="hljs-literal">null</span> || bytes.length == <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">String</span>(Base64.encodeBase64(bytes, <span class="hljs-literal">false</span>), CHARSET_UTF8);
}
public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(<span class="hljs-built_in">String</span>[] args) {
    <span class="hljs-built_in">String</span> str = <span class="hljs-string">"GET&amp;%2F&amp;AccessKeyId%3DCd***eHJuMOrT%26Action%3DDescribeInstances%26Format%3DJSON%26RegionId%3Dcn-hangzhou%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D9fdf288**36082ebef%26SignatureVersion%3D1.0%26Timestamp%3D2015-12-21T09%253A05%253A44Z%26Version%3D2014-05-26"</span>;
    byte[] signBytes;
    <span class="hljs-keyword">try</span> {
        signBytes = SignatureUtils.hmacSHA1Signature(<span class="hljs-string">"byc****6HQmH"</span> + <span class="hljs-string">"&amp;"</span>, str.toString());
        <span class="hljs-built_in">String</span> signature = SignatureUtils.newStringByBase64(signBytes);
    } <span class="hljs-keyword">catch</span> (Exception e) {
        <span class="hljs-comment">// TODO Auto-generated catch block</span>
        e.printStackTrace();
    }
}

}


4、Main方法


import com.google.common.collect.Maps;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.UUID;

public class Demo1 {

private <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> getQueryUrl(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; param, <span class="hljs-built_in">String</span> accessKeyId, <span class="hljs-built_in">String</span> secret) throws Exception {
    <span class="hljs-built_in">Date</span> date = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
    SimpleDateFormat simpleDateFormat = <span class="hljs-keyword">new</span> SimpleDateFormat(<span class="hljs-string">"yyyy-MM-dd'T'HH:mm:ss'Z'"</span>);
    simpleDateFormat.setTimeZone(<span class="hljs-keyword">new</span> SimpleTimeZone(<span class="hljs-number">0</span>, <span class="hljs-string">"GMT"</span>));
    <span class="hljs-built_in">String</span> timestamp = simpleDateFormat.format(date);
    <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; publicParam = Maps.newHashMap();

    publicParam.put(<span class="hljs-string">"AccessKeyId"</span>, accessKeyId);
    publicParam.put(<span class="hljs-string">"Format"</span>, <span class="hljs-string">"json"</span>);
    publicParam.put(<span class="hljs-string">"SignatureMethod"</span>, <span class="hljs-string">"Hmac-SHA1"</span>);
    publicParam.put(<span class="hljs-string">"SignatureNonce"</span>, UUID.randomUUID().toString());
    publicParam.put(<span class="hljs-string">"SignatureVersion"</span>, <span class="hljs-string">"1.0"</span>);
    publicParam.put(<span class="hljs-string">"Timestamp"</span>, timestamp);
    publicParam.put(<span class="hljs-string">"Version"</span>, <span class="hljs-string">"2018-12-03"</span>);
    publicParam.put(<span class="hljs-string">"RegionId"</span>, <span class="hljs-string">"cn-shanghai"</span>);

    <span class="hljs-keyword">if</span> (param != <span class="hljs-literal">null</span>) {
        <span class="hljs-keyword">for</span> (<span class="hljs-built_in">Map</span>.Entry&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; entry : param.entrySet()) {
            publicParam.put(entry.getKey(), entry.getValue());
        }
    }

    <span class="hljs-built_in">String</span> s = SignatureUtils.generateSignString(<span class="hljs-string">"POST"</span>, publicParam);
    byte[] signBytes;
    signBytes = SignatureUtils.hmacSHA1Signature(secret + <span class="hljs-string">"&amp;"</span>, s);
    <span class="hljs-built_in">String</span> signature = SignatureUtils.newStringByBase64(signBytes);

    publicParam.put(<span class="hljs-string">"Signature"</span>, signature);

    <span class="hljs-built_in">String</span> url = <span class="hljs-string">"http://face.cn-shanghai.aliyuncs.com/?"</span>;
    <span class="hljs-comment">//对参数进行url编码</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">Map</span>.Entry&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; entry : publicParam.entrySet()) {
        publicParam.put(entry.getKey(), URLEncoder.encode(entry.getValue().toString(), <span class="hljs-string">"UTF-8"</span>));
    }
    <span class="hljs-comment">//拼接请求url</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">Map</span>.Entry&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; entry : publicParam.entrySet()) {
        url = url + entry + <span class="hljs-string">"&amp;"</span>;
    }
    <span class="hljs-comment">//去掉最后一个&amp;</span>
    url = url.substring(<span class="hljs-number">0</span>, url.length() - <span class="hljs-number">1</span>);
    <span class="hljs-keyword">return</span> url;
}

public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(<span class="hljs-built_in">String</span>[] args) {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; map = Maps.newHashMap();
        map.put(<span class="hljs-string">"Action"</span>, <span class="hljs-string">"DetectFace"</span>);
        <span class="hljs-built_in">String</span> imageUrl_1 = <span class="hljs-string">"https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1559655604341&amp;di=3d6995f6dee1c4795d1827e754a00452&amp;imgtype=0&amp;src=http%3A%2F%2Fimg0.ph.126.net%2F90u9atgu46nnziAm1NMAGw%3D%3D%2F6631853916514183512.jpg"</span>;
        map.put(<span class="hljs-string">"ImageUrl"</span>,imageUrl_1);

        <span class="hljs-comment">// access_key_id, access_key_secret  获取参考链接:https://yq.aliyun.com/articles/693979?spm=a2c4e.11155435.0.0.319326a2bKJ90g</span>
        <span class="hljs-built_in">String</span> accessKeyId = <span class="hljs-string">"*******"</span>;
        <span class="hljs-built_in">String</span> secret = <span class="hljs-string">"*******"</span>;
        <span class="hljs-built_in">String</span> url = getQueryUrl(map, accessKeyId, secret);

        <span class="hljs-comment">// 使用生成的 URL 创建POST请求</span>
        URIBuilder builder = <span class="hljs-keyword">new</span> URIBuilder(url);
        URI uri = builder.build();
        HttpPost request = <span class="hljs-keyword">new</span> HttpPost(uri);
        HttpClient httpclient = HttpClients.createDefault();

        HttpResponse response = httpclient.execute(request);
        HttpEntity entity = response.getEntity();

        <span class="hljs-keyword">if</span> (entity != <span class="hljs-literal">null</span>)
        {
            System.out.println(EntityUtils.toString(entity));
        }
    }
    <span class="hljs-keyword">catch</span> (Exception e)
    {
        System.out.println(e.getMessage());
    }
}

}


5、运行结果


参考链接


签名算法参考

上一篇:阿里云老版人脸识别使用流程简介


下一篇:mysql优化(1)show命令 慢查询日志 explain profiling