APIインターフェース署名生成アルゴリズムと署名検証アルゴリズム


1、インターネット資料と本資料を参考にして、APIインタフェース署名生成アルゴリズムと署名検証アルゴリズムを実現しました.
(1)参考資料:https://www.jianshu.com/p/d47da77b6419
(2)参考書:高級ソフトウェア構築師教程(311-12)
 
2、APIインターフェース署名生成アルゴリズム
主な手順は以下の通りです.
(1)すべての業務要求パラメータをアルファベット順に並べ替える.
(2)パラメータ名とパラメータ値は、文字列Aにリンクされています.
(3)文字列Aの先頭にapiSecretインターフェースの隠しスプーンを加えて、新しい文字列Bを構成する.
(4)文字列をMD 5ハッシュ演算し、API署名signを得てからBase 64符号化を行う.
 
要求されたパラメータはf=1,b=23,k=33で、並べ替え後はb=23,f=1,k=33で、パラメータ名とパラメータ値をリンクした後はb 23 f 1 k 33で、最初の尾にappecretを加えた後md 5:
C=md 5(secretkey 1 value 1 key 2 value 2...secret);
Base 646.encode(C)
 
以上の署名方法は安全で効果的にパラメータの改竄と身分認証の問題を解決しました.もしパラメータが改竄されたら大丈夫です.他の人がapiSecretを知ることができなくて、新しいsignを再生成できなくなり、インタフェースの呼び出しが信頼できると保証します.
Javaコード
/**

*      HTTP    

* @param method

* @param path

* @param params

* @param apiKey

* @param apiSecret

*/

void addRequiredParams(String method, String path, Map params, String apiKey, String apiSecret) {

params.put("key", apiKey); //  

params.put("sigVer", "1"); //    

String ts = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now());

params.put("ts", ts); //   

params.put("nonce", RandomStringUtils.randomAlphanumeric(16));

String sig = getSig(method, path, apiSecret, params);

params.put("sig", sig); //API  

}



/**

* API    

*

* @param method

* @param path

* @param apiSecret

* @param params

* @return

*/

private String getSig(String method, String path, String apiSecret, Map params) {

StringBuilder stringA = new StringBuilder();

///1、                  .

// 2、                A

Set keySet = new TreeSet<>(params.keySet());

for (String key : keySet) {

String value = params.get(key);

if (value == null) {

continue;

}

System.out.println(key + ":" + params.get(key));

stringA.append(key);

stringA.append("=");

stringA.append(params.get(key));

stringA.append("&");

}

stringA.setLength(stringA.length() - 1); // trim the last "&"



System.out.println("                A:" + stringA.toString());

logger.debug("                A:" + stringA.toString());



String unifiedString = method.toUpperCase() + ":" + path + ":" + stringA.toString();

logger.debug("unified string: " + unifiedString);



String sig = null;

///3、    A     apiSecret        B

StringBuilder stringB = new StringBuilder();

stringB.append(apiSecret).append(stringA).append(apiSecret);

try {

//4、      MD5        sign,     Base64  

byte[] bytes = Base64.getEncoder().encode(MD5Utils.md5(stringB.toString()).getBytes("UTF-8"));

sig = new String(bytes, "UTF-8");

} catch (Exception e) {

logger.error("getSig error: " + e.getMessage());

}

return sig;

}



 
3、署名検証アルゴリズム(インターフェース提供者検証インターフェース要求が信頼できるかどうかは、主なアルゴリズムとAPI署名を生成するアルゴリズムと同じである)
主な手順は以下の通りです.
1、要求側が携帯するAPIの署名を得る.
2、すべての業務要求パラメータをアルファベット順に並べ替える.
3、パラメータ名とパラメータ値を文字列Aにリンクします.
4、文字列Aの先頭にappiSecretインターフェースの隠しスプーンを加えて、新しい文字列Bを構成します.
5、新しい文字列BにMD 5ハッシュ演算を行い、サーバ端のAPI署名を生成し、クライアントのAPI署名をBase 64で復号し、署名の検証を開始する.
6、サーバ端で生成されたAPI署名がクライアント要求のAPI署名と一致する場合、要求は信頼され、そうでなければ信頼されない.
javaコード
/**

*   API      

* (1)            (     apiSecret          )

* (2)              apiSecret            。

* (3)              ,        。    ,        ,      。

*

* @param request

* @param apiSecret

* @return

*/

public static boolean checkSig(HttpServletRequest request, String apiSecret) throws IOException{



//1、        API  

String clientSig = null;

StringBuilder stringA = new StringBuilder();



Enumeration parameterNames = request.getParameterNames();

Set keySet = new TreeSet<>();

//2、                  。

while (parameterNames.hasMoreElements()) {

String parameterName = parameterNames.nextElement();

if (parameterName.equals("sig")) {

//      API  

clientSig = request.getParameter("sig");

continue;

}

keySet.add(parameterName);

}

//3、                A。

for (String key : keySet) {

String value = request.getParameter(key);

if (value == null) {

continue;

}

stringA.append(key);

stringA.append("=");

stringA.append(value);

stringA.append("&");

}

stringA.setLength(stringA.length() - 1); // trim the last "&"

//             

String serverSig = null;

//Base64        

clientSig = new String(Base64.getDecoder().decode(clientSig), "UTF-8");

//4、    A     apiSecret            B。

StringBuilder stringB = new StringBuilder();

stringB.append(apiSecret).append(stringA).append(apiSecret);



//5、     B  MD5           API  ,     API    Base64  ,        。

//6、         API         API      ,       ,        。

serverSig = MD5Utils.md5(stringB.toString());

return clientSig != null && serverSig != null && clientSig.equals(serverSig);

}





3、          OpenApi     API    

        :          ,   API  。             ,   API             。

       :

/**

*   :   OpenAPI        

*

* @author chenlw

* @create 2018-11-19 11:21

*/

public class OpenApiRequestCheckFilter implements Filter {



@Autowired

private SystemConnectionConfigClient systemConnectionConfigClient;





@Override

public void init(FilterConfig filterConfig) throws ServletException {



}





@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {

System.out.println("-----------------OpenApiRequestCheckFilter--------------------");

HttpServletRequest request = (HttpServletRequest) servletRequest;

HttpServletResponse response = (HttpServletResponse) servletResponse;



if (systemConnectionConfigClient == null) {

//  @Autowired         

BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());

systemConnectionConfigClient = (SystemConnectionConfigClient) factory.getBean("systemConnectionConfigClient");

}



String apiKey = request.getParameter("key"); //apiKey

if(apiKey == null){

///API      ,              Controller

UnauthorizedForward(request,response);

return;

}

String apiSecret = systemConnectionConfigClient.queryDcToFrontApiSecretByApiKey(apiKey);

//             

if (apiSecret != null) {

/// API        

boolean sigCheckResult = OpenApiRequestCheckUtils.checkSig(request, apiSecret);

if (sigCheckResult) {

//API      

chain.doFilter(request, response);

} else {

///API      ,              Controller

UnauthorizedForward(request,response);

}

} else {

///API      ,              Controller

UnauthorizedForward(request,response);

}

}





private void UnauthorizedForward(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{

///        ,              Controller

if ("GET".equals(request.getMethod())) {

request.getRequestDispatcher("/api/dataCenterRequest/handleUnauthorizedGetRequest").forward(request, response);

} else {

request.getRequestDispatcher("/api/dataCenterRequest/handleUnauthorizedPostRequest").forward(request, response);

}

}



@Override

public void destroy() {



}

}