1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 简单API接口签名验证设计

简单API接口签名验证设计

时间:2022-06-25 20:57:33

相关推荐

简单API接口签名验证设计

前言

后端在写对外的API接口时,一般会对参数进行签名来保证接口的安全性,在设计签名算法的时候,主要考虑的是这几个问题:1. 请求的来源是否合法2. 请求参数是否被篡改3. 请求的唯一性我们的签名加密也是主要针对这几个问题来实现

设计

基于上述的几个问题,我们来通过已下步骤来实现签名加密:1. 通过分配给APP对应的app_key和app_secret来验证身份2. 通过将请求的所有参数按照字母先后顺序排序后拼接再MD5加密老保证请求参数不被篡改3. 请求里携带时间戳参数老保证请求的唯一和过期,重复的请求在指定时间(可配置)内有效

实现

签名生成:

生成当前时间戳timestamp=now按照请求参数名的字母升序排列非空请求参数(包含accessKey)stringA="AccessKey=access&home=world&name=hello&work=java&timestamp=now&nonce=random";拼接密钥accessSecretstringSignTemp="AccessKey=access&home=world&name=hello&work=java&timestamp=now&nonce=random&accessSecret=secret";MD5并转换为大写生成签名sign=MD5(stringSignTemp).toUpperCase();

JAVA代码如下:params是从request里面获取的所有参数map,accessSecret是加密密钥

private String createSign(Map<String, Object> params, String accessSecret) throws UnsupportedEncodingException {Set<String> keysSet = params.keySet();Object[] keys = keysSet.toArray();Arrays.sort(keys);StringBuilder temp = new StringBuilder();boolean first = true;for (Object key : keys) {if (first) {first = false;} else {temp.append("&");}temp.append(key).append("=");Object value = params.get(key);String valueString = "";if (null != value) {valueString = String.valueOf(value);}temp.append(valueString);}temp.append("&").append(ACCESS_SECRET).append("=").append(accessSecret);return MD5Util.MD52(temp.toString()).toUpperCase();}

签名校验:

参数格式校验超时校验验证签名

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Map<String, Object> result = new HashMap<String, Object>();String timestamp = request.getParameter(TIMESTAMP_KEY);String accessKey = request.getParameter(ACCESS_KEY);String accessSecret = map.get(accessKey);if (!mons.lang.StringUtils.isNumeric(timestamp)) {result.put("code", 1000);result.put("msg", "请求时间戳不合法");WebUtils.writeJsonByObj(result, response, request);return false;}// 检查KEY是否合理if (StringUtils.isEmpty(accessKey) || StringUtils.isEmpty(accessSecret)) {result.put("code", 1001);result.put("msg", "加密KEY不合法");WebUtils.writeJsonByObj(result, response, request);return false;}Long ts = Long.valueOf(timestamp);// 禁止超时签名if (System.currentTimeMillis() - ts > SIGN_EXPIRED_TIME) {result.put("code", 1002);result.put("msg", "请求超时");WebUtils.writeJsonByObj(result, response, request);return false;}if (!verificationSign(request, accessKey, accessSecret)) {result.put("code", 1003);result.put("msg", "签名错误");WebUtils.writeJsonByObj(result, response, request);return false;}return true;}

校验签名

private boolean verificationSign(HttpServletRequest request, String accessKey, String accessSecret) throws UnsupportedEncodingException {Enumeration<?> pNames = request.getParameterNames();Map<String, Object> params = new HashMap<String, Object>();while (pNames.hasMoreElements()) {String pName = (String) pNames.nextElement();if (SIGN_KEY.equals(pName)) continue;Object pValue = request.getParameter(pName);params.put(pName, pValue);}String originSign = request.getParameter(SIGN_KEY);String sign = createSign(params, accessSecret);return sign.equals(originSign);}

完整代码:

这里通过拦截器来实现接口拦截,可自行替换

package com.mon.web.interceptor;import com.mlcs.core.conf.ZKClient;import com.mon.web.util.MD5Util;import com.mon.web.util.WebUtils;import org.apache.zookeeper.KeeperException;import org.springframework.util.StringUtils;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.StringReader;import java.io.UnsupportedEncodingException;import java.util.*;import java.util.concurrent.ConcurrentHashMap;/*** Author: Kelin* Date: /5/16* Description:*/@SuppressWarnings("SuspiciousMethodCalls")public class SimpleApiSignInterceptor extends HandlerInterceptorAdapter {// 签名超时时长,默认时间为5分钟,msprivate static final int SIGN_EXPIRED_TIME = 5 * 60 * 1000;private static final String API_SIGN_KEY_CONFIG_PATH = "/mop/common/system/api_sign_key_mapping.properties";private static final String SIGN_KEY = "sign";private static final String TIMESTAMP_KEY = "timestamp";private static final String ACCESS_KEY = "accessKey";private static final String ACCESS_SECRET = "accessSecret";private static Map<String, String> map = new ConcurrentHashMap<String, String>();static {// 从zk加载key映射到内存里面try {String data = ZKClient.get().getStringData(API_SIGN_KEY_CONFIG_PATH);Properties properties = new Properties();properties.load(new StringReader(data));for (Object key : properties.keySet()) {map.put(String.valueOf(key), properties.getProperty(String.valueOf(key)));}} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Map<String, Object> result = new HashMap<String, Object>();String timestamp = request.getParameter(TIMESTAMP_KEY);String accessKey = request.getParameter(ACCESS_KEY);String accessSecret = map.get(accessKey);if (!mons.lang.StringUtils.isNumeric(timestamp)) {result.put("code", 1000);result.put("msg", "请求时间戳不合法");WebUtils.writeJsonByObj(result, response, request);return false;}// 检查KEY是否合理if (StringUtils.isEmpty(accessKey) || StringUtils.isEmpty(accessSecret)) {result.put("code", 1001);result.put("msg", "加密KEY不合法");WebUtils.writeJsonByObj(result, response, request);return false;}Long ts = Long.valueOf(timestamp);// 禁止超时签名if (System.currentTimeMillis() - ts > SIGN_EXPIRED_TIME) {result.put("code", 1002);result.put("msg", "请求超时");WebUtils.writeJsonByObj(result, response, request);return false;}if (!verificationSign(request, accessKey, accessSecret)) {result.put("code", 1003);result.put("msg", "签名错误");WebUtils.writeJsonByObj(result, response, request);return false;}return true;}private boolean verificationSign(HttpServletRequest request, String accessKey, String accessSecret) throws UnsupportedEncodingException {Enumeration<?> pNames = request.getParameterNames();Map<String, Object> params = new HashMap<String, Object>();while (pNames.hasMoreElements()) {String pName = (String) pNames.nextElement();if (SIGN_KEY.equals(pName)) continue;Object pValue = request.getParameter(pName);params.put(pName, pValue);}String originSign = request.getParameter(SIGN_KEY);String sign = createSign(params, accessSecret);return sign.equals(originSign);}private String createSign(Map<String, Object> params, String accessSecret) throws UnsupportedEncodingException {Set<String> keysSet = params.keySet();Object[] keys = keysSet.toArray();Arrays.sort(keys);StringBuilder temp = new StringBuilder();boolean first = true;for (Object key : keys) {if (first) {first = false;} else {temp.append("&");}temp.append(key).append("=");Object value = params.get(key);String valueString = "";if (null != value) {valueString = String.valueOf(value);}temp.append(valueString);}temp.append("&").append(ACCESS_SECRET).append("=").append(accessSecret);return MD5Util.MD52(temp.toString()).toUpperCase();}}

原文:/KelinM/blog/1925209

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。