工作实战之系统交互api调用认证设计

在系统开发过程中,系统与系统之间往往不是完全独立的,需要进行互相调用

黄金段位:直接http访问api接口,获取相关数据

钻石段位:定义接口规范,发放授权,api接口需要认证授权才能访问

星耀段位:提供sdk客户端,封装调用api接口所需要的加解密以及http访问的工具类

王者段位:sdk进一步封装,封装成近似本地调用的api接口,调用方只需配置appId,appSecret,接口域名即可,采用springboot自动装配,开发自己的starter


一、黄金段位接口交互

 public String doPost(String host, String uri, String body, String method) {
        try {
            String address = host + uri;
            URL restServiceURL = new URL(address);
            HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL.openConnection();
            httpConnection.setRequestMethod(method);
            httpConnection.setDoOutput(true);
            httpConnection.setDoInput(true);
            httpConnection.setRequestProperty("Content-Type", "application/json");
 
             OutputStream outputStream = httpConnection.getOutputStream();
        outputStream.write(body.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        if (httpConnection.getResponseCode() != 200) {
            throw new RuntimeException("Failed : HTTP outor code : " + httpConnection.getResponseCode());
        }
        BufferedReader responseBuffer = new BufferedReader(new InputStreamReader(httpConnection.getInputStream(), "UTF-8"));
        StringBuilder output = new StringBuilder();
        do {
            output.append(responseBuffer.readLine());
        } while (responseBuffer.read() != -1);
        httpConnection.disconnect();
        return output.toString();

        } catch (Exception e) {
            LOGGER.error("请求post接口报错:{}", e);
        }
        return null;
    }

二、钻石段位接口交互设计

1.接口文档定义

账号:appId; 授权密钥:appSecret;http每次请求header中需要添加appId、randomcode、timestamp、encodekey、sign五个参数,接口将使用这五个参数进行鉴权判断请求方式是否可以使用当前API

序号

参数名

参数类型

描述

值(样例)

1

appId

String必填

授权帐号

liangxi.zeng

2

randomcode

String必填

随机生成的字符串(每次可不相同)

2sd4TeSk

3

timestamp

String必填

当前时间戳

20150917160500

4

encodekey

String必填

前三个参数拼在一起后加上SIM授权的密钥appSecret作为salt使用SHA-256算法进行加密

8729e01cb547sdc3ea645aaa9f8493ab251e5ef32c3d6628cf85f985319145e3

5

sign

String必填

签名信息,采用MD5加密,计算公式接口:sign=MD5(uri&body&appSecret),有些接口可能没有body,参数是在URL中,则将body置为空串进行签名

6

appSecretString必填

加解密双方约定自定义的字符串,用作加密,不能直接放入header

o10ympt70x8gqas8hpoctopk3lwrdfd

7Content-TypeString必填参数提交方式application/Json

 

2.工具类以及demo提供

a.调用方部分代码

加解密工具类DigestUtils


   publicvoid setHeader(HttpURLConnection httpConnection,String uri,String body,String method) throws ProtocolException {
       httpConnection.setRequestMethod(method);
       httpConnection.setDoOutput(true);
       httpConnection.setDoInput(true);
       httpConnection.setRequestProperty("Content-Type", "application/json");
       httpConnection.setRequestProperty("appId", appId);
       String randomCode = RandomStringUtils.random(16, true, true);
       httpConnection.setRequestProperty("randomcode", randomCode);
       String dateNow = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss");
       httpConnection.setRequestProperty("timestamp", dateNow);
       //加密
       String encodeKey = DigestUtils.sha256Hex(StringUtils.join(appUser, randomCode, dateNow, "{", privateKey, "}"));
       httpConnection.setRequestProperty("encodekey", encodeKey);
       //签名
       String sign = DigestUtils.md5Hex(StringUtils.join(uri, "&", body, "&", privateKey));
       httpConnection.setRequestProperty("sign", sign.toUpperCase(Locale.ROOT));
   }


 public String doPost(String host, String uri, String body, String method) {
        try {
            String address = host + uri;
            URL restServiceURL = new URL(address);
            HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL.openConnection();

            //设置加解密参数认证参数
            setHeader(httpConnection,url,body,method);
 
             OutputStream outputStream = httpConnection.getOutputStream();
        outputStream.write(body.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        if (httpConnection.getResponseCode() != 200) {
            throw new RuntimeException("Failed : HTTP outor code : " + httpConnection.getResponseCode());
        }
        BufferedReader responseBuffer = new BufferedReader(new InputStreamReader(httpConnection.getInputStream(), "UTF-8"));
        StringBuilder output = new StringBuilder();
        do {
            output.append(responseBuffer.readLine());
        } while (responseBuffer.read() != -1);
        httpConnection.disconnect();
        return output.toString();

        } catch (Exception e) {
            LOGGER.error("请求post接口报错:{}", e);
        }
        return null;
    }

b.被调用方

对请求头里传入的参数进行一一校验即可,设计成过滤器拦截,提供给外部的接口都需要认证鉴权

三.星耀段位接口访问设计

1.在钻石段位的基础上,进行sdk的封装

     a.maven引入

<dependency>
		<groupId>com.tcl.api.auth</groupId>
        <artifactId>auth-util</artifactId>
        <version>2.2.0-RELEASE<</version>
</dependency>

   b.sdk包含工具类


/**
 * api 访问工具类
 * @author liangxi.zeng
 */
@Slf4j
public class ApiHttpUtils {

    /**
     * 设置请求同
     * @param httpConnection
     * @param uri
     * @param appId
     * @param body
     * @param method
     * @throws ProtocolException
     */
    private static void setRequestHeader(HttpURLConnection httpConnection
            , String uri,String appId,String appSecret
            , String body
            , String method) throws ProtocolException {
        httpConnection.setRequestMethod(method);
        httpConnection.setDoOutput(true);
        httpConnection.setDoInput(true);
        httpConnection.setRequestProperty("Content-Type", "application/json");
        httpConnection.setRequestProperty("appuser", appId);
        String randomCode = RandomStringUtils.random(16, true, true);
        httpConnection.setRequestProperty("randomcode", randomCode);
        log.debug("randomcode:{}", randomCode);
        String dateNow = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss'Z'");
        log.debug("dateNow:{}", dateNow);
        httpConnection.setRequestProperty("timestamp", dateNow);
        //加密
        String encodeKey = DigestUtils.sha256Hex(StringUtils.join(appId, randomCode, dateNow, "{", appSecret, "}"));
        log.debug("encodeKey:{}", encodeKey);
        httpConnection.setRequestProperty("encodekey", encodeKey);
        //签名
        String sign = DigestUtils.md5Hex(StringUtils.join(uri, "&", body, "&", appSecret));
        log.debug("sign:{}", sign);
        httpConnection.setRequestProperty("sign", sign.toUpperCase(Locale.ROOT));
    }

    /**
     * 发送post请求
     * @param host
     * @param uri
     * @param body
     * @return
     */
    public static String doPost(String host, String uri, String body
            ,String appId,String appSecret) {
        try {
            String address = host + uri;
            log.debug("appuser:{},privateket:{},address:{}", appId, appSecret,address);
            URL restServiceURL = new URL(address);
            HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL.openConnection();
            setRequestHeader(httpConnection,uri,body,appId,appSecret,"POST");
            return getResponse(httpConnection,body);
        } catch (Exception e) {
            log.error("请求idm post接口报错:{}", e);
        }
        return null;
    }

    /**
     * 发送post请求
     * @param host
     * @param uri
     * @param body
     * @return
     */
    public static String doGet(String host, String uri, String body
            ,String appId,String appSecret) {
        try {
            String address = host + uri;
            log.debug("appuser:{},privateket:{},address:{}", appId, appSecret,address);
            URL restServiceURL = new URL(address);
            HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL.openConnection();
            setRequestHeader(httpConnection,uri,body,appId,appSecret,"GET");
            return getResponse(httpConnection,body);
        } catch (Exception e) {
            log.error("请求idm post接口报错:{}", e);
        }
        return null;
    }

    /**
     * 获取响应内容
     * @param httpConnection
     * @param body
     * @return
     * @throws IOException
     */
    private static String getResponse(HttpURLConnection httpConnection,String body) throws IOException {
        OutputStream outputStream = httpConnection.getOutputStream();
        outputStream.write(body.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        if (httpConnection.getResponseCode() != 200) {
            throw new RuntimeException("Failed : HTTP outor code : " + httpConnection.getResponseCode());
        }
        BufferedReader responseBuffer = new BufferedReader(new InputStreamReader(httpConnection.getInputStream(), "UTF-8"));
        StringBuilder output = new StringBuilder();
        do {
            output.append(responseBuffer.readLine());
        } while (responseBuffer.read() != -1);
        httpConnection.disconnect();
        return output.toString();
    }


}

四.王者段位接口访问设计 

1.开发详情

a.基于springboot的spring.factories开发自己的starter

b.采用openFeign实现http远程接口访问

c.用FeignRequestInterceptor完成请求头的权限认证参数放入

2.项目结构

3.系统侧使用

api:
  auth:
    appId: 12323
    appSecret: lakdsjlajdsljajskdjf
    domain: https://sp.tcl.com/portal/
<dependency>
		<groupId>com.tcl.ea.zenglx</groupId>
        <artifactId>api-auth-spring-boot-starter</artifactId>
        <version>1.0-SNAPSHOT</version>
</dependency>
@Service
public class RemoteDeal {

    @Autowired
    private ApiClient apiClient;

    //获取用户信息
    
    public User getUserInfo() {
        
        return apiClient.getUserInfo();

    }

}

 4.源码下载

api认证源码


总结

 1.发起http请求的开源框架有, Forest,httpClient,feign,OKHttp等

 2.开发组件需要了解spring的生命周期,各种特性,springboot的各种特性

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值