springboot封装 涂鸦物联网平台API鉴权请求的demo

  • 先看依赖
    
    
        org.springframework.boot
        spring-boot-starter-data-redis
    
    
    
        org.apache.httpcomponents
        httpclient
    
    
    
        org.apache.httpcomponents
        httpasyncclient
    
    
    
        org.bgee.log4jdbc-log4j2
        log4jdbc-log4j2-jdbc4.1
        1.16
    

    封装的助手类中主要使用httpclient作为请求管理类;并且使用了redis作为缓存提供者,没有用redis的使用其他缓存也可以;
    看一下我的redis缓存实现类
     

    package com.abon.smart_family_lot.application.common.util;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * desc: redis缓存助手类
     * author: zmq3821@163.com
     * date: 2021/12/2 15:09
     */
    @Component
    public class RedisCacheUtil {
    
        private StringRedisTemplate stringRedisTemplate;
    
        @Autowired
        public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
            this.stringRedisTemplate = stringRedisTemplate;
        }
    
        // 设置缓存
        public void set(String key, String value) {
            stringRedisTemplate.opsForValue().set(key, value);
        }
    
        // 设置缓存
        public void set(String key, String value, long expire) {
            stringRedisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
        }
    
        // 获取缓存值
        public String get(String key) {
            return stringRedisTemplate.opsForValue().get(key);
        }
    
        // 设置有效期
        public boolean expire(String key, long expire) {
            return Boolean.TRUE.equals(stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS));
        }
    
        // 清理缓存
        public void remove(String key) {
            if (hasKey(key)) {
                stringRedisTemplate.delete(key);
            }
        }
    
        // 缓存递增
        public Long increment(String key, long delta) {
            return stringRedisTemplate.opsForValue().increment(key, delta);
        }
    
        // 是否存在指定缓存
        public boolean hasKey(String key) {
            return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
        }
    
    
    }
    
  • 先看一下我的目录结构,只是为了方便搞清楚代码存放的逻辑。红框里的就是主要使用到文件

 springboot封装 涂鸦物联网平台API鉴权请求的demo

  1. 先在resources创建tuya.yml
    #云端
    cloud:
      client-id: xxx #授权密钥
      client-secret: xxxxxxxxxx #授权密钥
      endpoint: https://openapi.tuyacn.com #接入地址-中国数据中心
    
    
  2. 在common/config中创建TuyaCloudConfig.java

    package com.abon.smart_family_lot.application.common.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    @Data
    @Configuration
    @PropertySource(value = {"classpath:tuya.yml"}, encoding = "utf-8", factory = YamlConfigFactory.class)
    @ConfigurationProperties(prefix = "cloud")
    public class TuyaCloudConfig {
    
        private String clientId;
    
        private String clientSecret;
    
        private String endpoint;
    
    }
    

    这里用到了 YamlConfigFactory,用于辅助加载yml文件

    package com.abon.smart_family_lot.application.common.config;
    
    import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
    import org.springframework.core.env.PropertiesPropertySource;
    import org.springframework.core.env.PropertySource;
    import org.springframework.core.io.support.DefaultPropertySourceFactory;
    import org.springframework.core.io.support.EncodedResource;
    import org.springframework.lang.Nullable;
    
    import java.io.IOException;
    import java.util.Properties;
    
    public class YamlConfigFactory extends DefaultPropertySourceFactory {
    
        @Override
        public PropertySource> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
            String sourceName = name != null ? name : resource.getResource().getFilename();
            if (!resource.getResource().exists()) {
                assert sourceName != null;
                return new PropertiesPropertySource(sourceName, new Properties());
            } else {
                assert sourceName != null;
                if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
                    Properties propertiesFromYaml = loadYml(resource);
                    return new PropertiesPropertySource(sourceName, propertiesFromYaml);
                } else {
                    return super.createPropertySource(name, resource);
                }
            }
        }
    
        private Properties loadYml(EncodedResource resource) throws IOException {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        }
    
    }
    
  3. 创建请求基类BaseRequest

    package com.abon.smart_family_lot.application.common.extend.request;
    
    /**
     * desc: 请求基类
     * author: zmq3821@163.com
     * date: 2021/12/6 9:58
     */
    public class BaseRequest {
    
        private String error = "";
    
        private Object result = "";
    
        public void setError(String error) {
            this.error = error;
        }
    
        public String getError() {
            return error;
        }
    
        public void setResult(Object result) {
            this.result = result;
        }
    
        public Object getResult() {
            return result;
        }
    
    }
    
  4. 创建真正的请求封装类TuyaRequest.java

    package com.abon.smart_family_lot.application.common.extend.request.tuya;
    
    import com.abon.smart_family_lot.application.common.exception.TuyaCloudSDKException;
    import com.abon.smart_family_lot.application.common.extend.request.BaseRequest;
    import com.abon.smart_family_lot.application.common.util.HttpUtil;
    import com.alibaba.fastjson.JSONObject;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * desc: 涂鸦平台请求封装
     * author: zmq3821@163.com
     * date: 2021/12/6 10:00
     */
    @Slf4j
    @Component
    public class TuyaRequest extends BaseRequest {
    
        @Resource
        private TuyaRequestHelper tuyaRequestHelper;
    
        // GET请求
        public boolean doGetRequest(String uri, Map customHeaders) {
            Object _result;
            try {
                String accessToken = tuyaRequestHelper.getAccesToken();
                String url = tuyaRequestHelper.getUrlStr(uri, null);
                Map newHeaders = tuyaRequestHelper.getHeader("GET", url, customHeaders, null, accessToken);
                log.info("doGetRequest => Url: {}, headers: {}", uri, "n" + JSONObject.toJSONString(newHeaders));
                String response = HttpUtil.httpGet(url, newHeaders);
                log.info("response: {}", response);
                JSONObject responseObject = JSONObject.parseObject(response);
                Boolean success = responseObject.getBoolean("success");
                if (!success) {
                    throw new TuyaCloudSDKException(responseObject);
                }
                _result = responseObject.get("result");
                setResult(_result);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                setError(e.getMessage());
                return false;
            }
        }
    
        // POST请求
        public boolean doPostRequest(String uri, String body, Map customHeaders) {
            Object _result;
            try {
                if (customHeaders == null) {
                    customHeaders = new HashMap();
                }
                customHeaders.put("Content-Type", "application/json");
                String accessToken = tuyaRequestHelper.getAccesToken();
                String url = tuyaRequestHelper.getUrlStr(uri, null);
                Map newHeaders = tuyaRequestHelper.getHeader("POST", url, customHeaders, body, accessToken);
                log.info("doPostRequest => Url: {}, n body: {}, n headers: {}", uri, body, JSONObject.toJSONString(newHeaders));
                String response = HttpUtil.httpPost(url, body, newHeaders);
                log.info("response: {}", response);
                JSONObject responseObject = JSONObject.parseObject(response);
                Boolean success = responseObject.getBoolean("success");
                if (!success) {
                    throw new TuyaCloudSDKException(responseObject);
                }
                _result = responseObject.get("result");
                setResult(_result);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                setError(e.getMessage());
                return false;
            }
        }
    
        // PUT请求
        public boolean doPutRequest(String uri, String body, Map customHeaders) {
            Object _result;
            try {
                if (customHeaders == null) {
                    customHeaders = new HashMap();
                }
                customHeaders.put("Content-Type", "application/json");
                String accessToken = tuyaRequestHelper.getAccesToken();
                String url = tuyaRequestHelper.getUrlStr(uri, null);
                Map newHeaders = tuyaRequestHelper.getHeader("PUT", url, customHeaders, body, accessToken);
                log.info("doPutRequest => Url: {}, n body: {}, n headers: {}", uri, body, JSONObject.toJSONString(newHeaders));
                String response = HttpUtil.httpPut(url, body, newHeaders);
                log.info("response: {}", response);
                JSONObject responseObject = JSONObject.parseObject(response);
                Boolean success = responseObject.getBoolean("success");
                if (!success) {
                    throw new TuyaCloudSDKException(responseObject);
                }
                _result = responseObject.get("result");
                setResult(_result);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                setError(e.getMessage());
                return false;
            }
        }
    
        // DELETE请求
        public boolean doDeleteRequest(String uri, Map customHeaders) {
            Object _result;
            try {
                String accessToken = tuyaRequestHelper.getAccesToken();
                String url = tuyaRequestHelper.getUrlStr(uri, null);
                Map newHeaders = tuyaRequestHelper.getHeader("DELETE", url, customHeaders, null, accessToken);
                log.info("doDeleteRequest => Url: {}, headers: {}", uri, "n" + JSONObject.toJSONString(newHeaders));
                String response = HttpUtil.httpDelete(url, newHeaders);
                log.info("response: {}", response);
                JSONObject responseObject = JSONObject.parseObject(response);
                Boolean success = responseObject.getBoolean("success");
                if (!success) {
                    throw new TuyaCloudSDKException(responseObject);
                }
                _result = responseObject.get("result");
                setResult(_result);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                setError(e.getMessage());
                return false;
            }
        }
    
    
    
    }
    
  5. 创建请求的助手类TuyaRequestHelper,请求的授权签名和header处理都在这里了
    package com.abon.smart_family_lot.application.common.extend.request.tuya;
    
    import com.abon.smart_family_lot.application.common.config.TuyaCloudConfig;
    import com.abon.smart_family_lot.application.common.extend.request.BaseRequest;
    import com.abon.smart_family_lot.application.common.util.Sha256Util;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.nio.charset.StandardCharsets;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.TreeMap;
    import java.util.stream.Collectors;
    
    /**
     * desc: 涂鸦平台API SIGN辅助类
     * author: zmq3821@163.com
     * date: 2021/12/6 10:00
     */
    @Slf4j
    @Component
    public class TuyaRequestHelper extends BaseRequest {
    
        // 当body为空时的SHA256值
        private static final String EMPTY_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
    
        // 需要参与签名的Header的key
        private static final String SING_HEADER_NAME = "Signature-Headers";
    
        @Resource
        private TuyaCloudConfig tuyaCloudConfig;
    
        @Resource
        private TuyaRequestAccessToken tuyaRequestAccessToken;
    
        // header请求头参数初始化
        public Map getHeader(String method, String url, Map headerMap, String body, String accessToken) {
            Map flattenHeaders = flattenHeaders(headerMap);
            String t = System.currentTimeMillis() + "";
            String nonceStr = flattenHeaders.getOrDefault("nonce", "");
            String signatureHeaders = flattenHeaders.getOrDefault(SING_HEADER_NAME, "");
            Map headers = new HashMap(flattenHeaders);
            System.out.println("_headers:" + headers);
            headers.put("client_id", tuyaCloudConfig.getClientId());
            headers.put("t", t);
            headers.put("sign_method", "HMAC-SHA256");
            headers.put("lang", "zh"); // 语言类型。中国区默认 zh,其他区默认 en
            headers.put("nonce", nonceStr); // API调用者生成的UUID
            headers.put(SING_HEADER_NAME, signatureHeaders); // 开发者自定义需要加入签名的header字段。
            String stringToSign = stringToSign(method, url, body, flattenHeaders);
            if (StringUtils.isNotBlank(accessToken)) {
                headers.put("access_token", accessToken);
                headers.put("sign", sign(t, nonceStr, stringToSign, accessToken));
            } else {
                headers.put("sign", sign(t, nonceStr, stringToSign, null));
            }
            return headers;
        }
    
        // 签名算法
        // 令牌管理: sign = HMAC-SHA256(client_id + t + nonce + stringToSign, secret).toUpperCase()
        // 业务管理: sign = HMAC-SHA256(client_id + access_token + t + nonce + stringToSign, secret).toUpperCase()
        private String sign(String t, String nonce, String stringToSign, String accessToken) {
            String clientId = tuyaCloudConfig.getClientId();
            String secret = tuyaCloudConfig.getClientSecret();
            StringBuilder str = new StringBuilder();
            accessToken = StringUtils.isBlank(accessToken) ? "" : accessToken;
            nonce = StringUtils.isBlank(nonce) ? "" : nonce;
            str.append(clientId).append(accessToken).append(t).append(nonce).append(stringToSign);
            return Sha256Util.sha256HMAC(str.toString(), secret);
        }
    
        // 生成签名字符串
        public String stringToSign(String httpMethod, String url, String bodyStr, Map headers) {
            try {
                log.info("httpMethod:{}, url:{}, bodyStr:{}, headers:{}", httpMethod, url, bodyStr, headers);
                String sha256 = EMPTY_HASH;
                if (bodyStr != null && bodyStr.length() > 0) {
                    System.out.println("bodyStr:" + bodyStr);
                    sha256 = Sha256Util.encryption(bodyStr);
                }
                String headersStr = getSignHeaderStr(headers);
                String newUrl = getPathAndSortParam(new URL(url));
                log.info("生成签名字符串 => n httpMethod: {},sha256: {},headersStr: {}, newUrl: {}", httpMethod, sha256, headersStr, newUrl);
                return httpMethod.toUpperCase() + "n" + sha256 + "n" + headersStr + "n" + newUrl;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
        // 过滤header
        private static Map flattenHeaders(Map headers) {
            Map newHeaders = new HashMap();
            if (headers != null) {
                headers.forEach((name, values) -> {
                    if (values == null || values.isEmpty()) {
                        newHeaders.put(name, "");
                    } else {
                        newHeaders.put(name, values);
                    }
                });
            }
            return newHeaders;
        }
    
        // 返回参与签名计算的SignHeaderStr
        private String getSignHeaderStr(Map headers) {
            String headersStr = "";
            String signHeaderStr = headers.getOrDefault(SING_HEADER_NAME, "");
            if (StringUtils.isNotEmpty(signHeaderStr)) {
                String[] signHeaderKeys = signHeaderStr.split("s*:s*");
                headersStr = Arrays.stream(signHeaderKeys)
                        .map(String::trim)
                        .filter(it -> it.length() > 0)
                        .map(it -> it + ":" + headers.get(it))
                        .collect(Collectors.joining("n"));
            }
            return headersStr;
        }
    
        // 返回排序处理过的url
        public static String getPathAndSortParam(URL url) {
            String path = "";
            try {
                path = url.getPath();
                String query = "";
                if (StringUtils.isNotBlank(url.getQuery())) {
                    query = URLDecoder.decode(url.getQuery(), StandardCharsets.UTF_8);
                }
                if (StringUtils.isBlank(query)) {
                    return path;
                }
                Map kvMap = new TreeMap(); //红黑树排序
                String[] kvs = query.split("&");
                for (String kv : kvs) {
                    String[] kvArr = kv.split("=");
                    if (kvArr.length > 1) {
                        kvMap.put(kvArr[0], kvArr[1]);
                    } else {
                        kvMap.put(kvArr[0], "");
                    }
                }
                return path + "?" + kvMap.entrySet().stream().map(it -> it.getKey() + "=" + it.getValue())
                        .collect(Collectors.joining("&"));
            } catch (Exception ignored) {
            }
            return path;
        }
    
        // 拼接URL与参数
        public String getUrlStr(String path, Map querys) {
            String endpoint = tuyaCloudConfig.getEndpoint();
            StringBuilder urlStr = new StringBuilder();
            urlStr.append(endpoint);
            if (StringUtils.isNotBlank(path)) {
                urlStr.append(path);
            }
            if (querys != null) {
                StringBuilder paramsStr = new StringBuilder();
                querys.forEach((key, val) -> {
                    if (paramsStr.length() > 0) {
                        paramsStr.append("&");
                    }
                    if (StringUtils.isNotBlank(key)) {
                        paramsStr.append(key).append("=").append(val);
                    }
                });
                if (paramsStr.length() > 0) {
                    urlStr.append("?").append(paramsStr);
                }
            }
            return urlStr.toString();
        }
    
        // 返回accessToken
        public String getAccesToken() {
            return tuyaRequestAccessToken.getAccessToken();
        }
    
    
    }
    

    4

  6. 还要创建accessToekn管理类TuyaRequestAccessToken

    简单来说是把获取到的accessToken和refreshToken分别放入缓存中,若accessToken缓存到期则使用refreshToken刷新Token并再次放入缓存;TuyaRequestAccessToken由此实现了token的管理,而在请求内只需调用而无需关心accessToken的获取逻辑
     

    package com.abon.smart_family_lot.application.common.extend.request.tuya;
    
    import com.abon.smart_family_lot.application.common.exception.TuyaCloudSDKException;
    import com.abon.smart_family_lot.application.common.extend.request.BaseRequest;
    import com.abon.smart_family_lot.application.common.util.DateUtil;
    import com.abon.smart_family_lot.application.common.util.HttpUtil;
    import com.abon.smart_family_lot.application.common.util.RedisCacheUtil;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.io.Serializable;
    import java.util.Map;
    
    /**
     * desc: 涂鸦平台API accessToekn管理类
     * author: zmq3821@163.com
     * date: 2021/12/6 10:00
     */
    @Slf4j
    @Component
    public class TuyaRequestAccessToken {
    
        // accessToken的缓存键
        private final String cacheAccessTokenKey = "TUYA_API_ACCESS_TOKEN";
    
        // refreshToken的缓存键
        private final String cacheRefreshTokenKey = "TUYA_API_REFRESH_ACCESS_TOKEN";
    
        @Resource
        private TuyaRequestHelper tuyaRequestSign;
    
        @Resource
        private RedisCacheUtil redisCacheUtil;
    
    
        @Data
        @NoArgsConstructor // 注解在类上;为类提供一个无参的构造方法
        @AllArgsConstructor // 注解在类上;为类提供一个全参的构造方法
        public static class TokenVO implements Serializable {
    
            private String accessToken;
    
            private String refreshToken;
    
            private long expireTime;
    
        }
    
        // 获取AccessToken
        private void createAccessToken() {
            log.info("获取AccessToken");
            try {
                String uri = "/v1.0/token?grant_type=1";
                String url = tuyaRequestSign.getUrlStr(uri, null);
                Map newHeaders = tuyaRequestSign.getHeader("GET", url, null, null, null);
                log.info("doGetRequest => Url: {}, headers: {}", uri, "n" + JSONObject.toJSONString(newHeaders));
                String response = HttpUtil.httpGet(url, newHeaders);
                log.info("response: {}", response);
                JSONObject responseObject = JSONObject.parseObject(response);
                Boolean success = responseObject.getBoolean("success");
                if (!success) {
                    throw new RuntimeException(responseObject.getString("message"));
                }
                JSONObject data = responseObject.getJSONObject("result");
                TokenVO tokenVO = JSONObject.toJavaObject(data, TokenVO.class);
                long _expireTime = tokenVO.getExpireTime() - 10; //留出10秒避免临界值
                redisCacheUtil.set(cacheAccessTokenKey, tokenVO.getAccessToken(), _expireTime);
                redisCacheUtil.set(cacheRefreshTokenKey, tokenVO.getRefreshToken());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 刷新RefreshToken
        private void createRefreshToken(String refresh_token) {
            log.info("使用refreshToken换取accessToken");
            try {
                String uri = "/v1.0/token/" + refresh_token;
                String url = tuyaRequestSign.getUrlStr(uri, null);
                Map newHeaders = tuyaRequestSign.getHeader("GET", url, null, null, null);
                log.info("doGetRequest => Url: {}, headers: {}", uri, "n" + JSONObject.toJSONString(newHeaders));
                String response = HttpUtil.httpGet(url, newHeaders);
                log.info("response: {}", response);
                JSONObject responseObject = JSONObject.parseObject(response);
                Boolean success = responseObject.getBoolean("success");
                if (!success) {
                    throw new RuntimeException(responseObject.getString("message"));
                }
                JSONObject data = responseObject.getJSONObject("result");
                TokenVO tokenVO = JSONObject.toJavaObject(data, TokenVO.class);
                long _expireTime = tokenVO.getExpireTime() - 10; //留出10秒避免临界值
                redisCacheUtil.set(cacheAccessTokenKey, tokenVO.getAccessToken(), _expireTime);
                redisCacheUtil.set(cacheRefreshTokenKey, tokenVO.getRefreshToken());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 返回accessToken
        public String getAccessToken() {
            String _accessToken = redisCacheUtil.get(cacheAccessTokenKey);
            System.out.println("_accessToken:" + _accessToken);
            if (_accessToken == null) {
                String _refreshToken = redisCacheUtil.get(cacheRefreshTokenKey);
                System.out.println("_refreshToken:" + _refreshToken);
                if (_refreshToken == null) {
                    createAccessToken();
                } else {
                    createRefreshToken(_refreshToken);
                }
                return getAccessToken();
            } else {
                return _accessToken;
            }
        }
    
    
    }
    
  7. 最后示例一个GET请求的调用
     

    
    public boolean info(DeviceValidate.infoTDO params) {
        String deviceId = params.getDeviceId();
        boolean res = tuyaRequest.doGetRequest("/v1.0/devices/" + deviceId, null);
        if (!res) {
            setError(tuyaRequest.getError());
            return false;
        }
        JSONObject data = JSONObject.parseObject(tuyaRequest.getResult().toString());
        setResult(data);
        return true;
    
    }

8.应某位小伙伴的要求再补加一个Sha256Util工具类

package com.abon.smart_family_lot.application.common.util;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * desc: Sha256工具类
 * author: zmq3821@163.com
 * date: 2021/12/3 16:07
 */
public class Sha256Util {

    public static String encryption(String str) throws Exception {
        return encryption(str.getBytes(StandardCharsets.UTF_8));
    }

    public static String encryption(byte[] buf) throws Exception {
        MessageDigest messageDigest;
        messageDigest = MessageDigest.getInstance("SHA-256");
        messageDigest.update(buf);
        return byte2Hex(messageDigest.digest());
    }

    private static String byte2Hex(byte[] bytes) {
        StringBuilder stringBuffer = new StringBuilder();
        String temp;
        for (byte aByte : bytes) {
            temp = Integer.toHexString(aByte & 0xFF);
            if (temp.length() == 1) {
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }

    public static String sha256HMAC(String content, String secret) {
        Mac sha256HMAC = null;
        try {
            sha256HMAC = Mac.getInstance("HmacSHA256");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKey secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        try {
            assert sha256HMAC != null;
            sha256HMAC.init(secretKey);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        byte[] digest = sha256HMAC.doFinal(content.getBytes(StandardCharsets.UTF_8));
        return new HexBinaryAdapter().marshal(digest).toUpperCase();
    }


}

本文章来源于互联网,如有侵权,请联系删除!原文地址:springboot封装 涂鸦物联网平台API鉴权请求的demo

相关推荐: 物联网解决方案架构及其流程

随着物联网或物联网解决方案的出现,许多行业都从提高生产力和运营可靠性的物联网技术中受益匪浅。物联网解决方案提供了一种设置,其中包括传感器、仪器、机器和许多其他连接设备,无需人工干预即可运行。本文将慢慢分解物联网解决方案架构,以更多地了解物联网实施的分步过程。 …