sign签名(from表单格式)

7 篇文章 0 订阅

做接口开发首先需要注意的是接口的安全性,接口的安全性可以用Https来做或者直接在服务器层面设置ip白名单,我用的是sign签名来确保接口的安全性。
sign签名是根据用户请求的参数和值(不包括sign),结合分配给客户端的秘钥(securityKey),通过算法生成的签名。在算签名时,首先要按照每组的key=value的字母顺序做排序(升序降序自己拿主意),然后对key和vaule(使用utf-8编码,特别注意包含中文的参数值的编码)连接成没有等于号的字符串;然后在最后加上客户端的秘钥(securityKey)然后通过算法生成签名。
在此需要注意,前端必传的字段有:
appkey(String类型,必填,调用者第三方公钥)
timeStamp(String类型,必填,当前时间戳 格式(自己拿主意,只要前后端一致就行))
sign(String类型,必填,(参数+必传参数+私钥(securityKey,))的算法加密串)
假如参数有:
String appkey=“abcd”
String timeStamp=“20190422125727”
String aaa=“aaa”
String bbb=“bbb”
该客户端的秘钥是securityKey=1234567890
按照key=value升序排序是
aaa=aaaappkey=abcdbbb=bbbtimeStamp=20190422125727
连接成没有等于号的字符串
aaaaaaappkeyabcdbbbbbbtimeStamp20190422125727
拼接客户端秘钥
aaaaaaappkeyabcdbbbbbbtimeStamp201904221257271234567890
然后使用加密算法加密
sign=(aaaaaaappkeyabcdbbbbbbtimeStamp201904221257271234567890)加密后的串
在贴代码之前需要和大家说的问题是,post请求获取参数是可能是form表单格式或者是json格式,不同的格式获取参数的方式也是不同的,这一片博文先用post请求的form表单格式写,下一篇博文再介绍json格式。

/**
     * @param httpServletRequest
     * @param httpServletResponse
     * @return void
     * @Description: 验证sign签名
     * @Author Zangdy
     * @CreateTime 2019/4/22 12:57
     */
    private boolean verifySign(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        // 签名
        String appKey = httpServletRequest.getParameter("appKey");
        String timeStamp = httpServletRequest.getParameter("timeStamp");
        String sign = httpServletRequest.getParameter("sign");
        // 判断参数是否为空
        if (StringUtils.isBlank(appKey) || StringUtils.isBlank(timeStamp) || StringUtils.isBlank(sign)) {
            DyTool.responseWriter(StatusEnum.APPTIMESIGNISNULL, httpServletResponse);  // (工具类)
            return false;
        } else {
            StringBuilder signSb = new StringBuilder();
            // 获取url里的请求参数
            Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
            for (String paraName : parameterMap.keySet()) {
                if (!"sign".equals(paraName)) {   // 拼接参数
                    signSb.append(paraName).append("=").append(parameterMap.get(paraName)[0]).append("&");
                }
            }
            String signNew = signSb.substring(0, signSb.length() - 1); // 获取拼接后的参数
            String[] signArr = signNew.split("&");
            Arrays.sort(signArr);  // 将参数排序
            signNew = DyTool.arrToString(signArr);  // (工具类)数组转字符串
            signNew = signNew.replace("=", "");
            signNew += securityKeyLocal;  // 拼接securityKey
            if (!sign.equals(SecuritySHATool.shaEncrypt(signNew))) {
                DyTool.responseWriter(StatusEnum.SIGNUNTRUE, httpServletResponse);  // (工具类)
                return false;
            }
            long time = new Date().getTime();  // 获取当前时间毫秒值
            try {
            //DyTool.timeStampToDateTime  工具类,将yyyyMMddHHmmss转成毫秒值
                if ((time - DyTool.timeStampToDateTime(timeStamp)) > (1000 * 60 * 5)) { // 一次请求签名在五分钟内
                    DyTool.responseWriter(StatusEnum.SIGNOUTTIME, httpServletResponse); // (工具类)
                    return false;
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return true;
    } 
        /**
     * @param timeStamp  yyyyMMddHHmmss格式时间戳
     * @return java.lang.Long
     * @Description: 将时间戳转为毫秒值   yyyyMMddHHmmss
     * @Author Zangdy
     * @CreateTime 2019/4/22 11:42
     */
    public static Long timeStampToDateTime(String timeStamp) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.parse(timeStamp).getTime();
    }
    /**
     * @param statusEnum  状态枚举类
     * @param response
     * @return java.lang.String
     * @Description: 发生错误时响应给请求者, 拦截器过滤器层面,需要HttpServletResponse
     * @Author Zangdy
     * @CreateTime 2019/4/22 11:09
     */
    public static void responseWriter(StatusEnum statusEnum, HttpServletResponse response) throws IOException {
        ResponseBody responseBody = new ResponseBody();
        responseBody.setStatus(statusEnum.getStatus());
        responseBody.setMessage(statusEnum.getMessage());
        response.setContentType("text/html; charset=UTF-8");
        response.getWriter().write(JSONObject.toJSONString(responseBody));
    }
/**
 * @Description:  状态枚举类
 * @Author: 臧东运
 * @CreateTime: 2019/4/22 10:53
 */
public enum  StatusEnum {

    UNLOGIN("0000","未登录"),

    /**
     * 状态 02 开头为成功
     * */
    LOGINSUCCESS("0201","登陆成功"),
    LOGOUTSUCCESS("0202","注销成功"),
    UPLOADSUCCESS("0203","文件上传成功"),


    /**
     * 状态 04 开头为失败
     */
    IPBLOCKED("0400","因非法请求,已被禁止访问,请稍后重试!"),
    ACCESSDENIED("0401","无权限访问"),
    USERNAMEISNULL("0402","用户名不能为空!"),
    PASSWORDISNULL("0402","密码不能为空!"),
    USERNAMEERROR("0402","用户名错误!"),
    PASSWORDERROR("0402","密码错误!"),
    NOHEADER("0403","缺少头信息"),
    TOKENOUTTIME("0404","token认证已过期"),
    APPTIMESIGNISNULL("0405","sign认证参数为空"),
    SIGNUNTRUE("0406","sign参数不正确"),
    SIGNOUTTIME("0407","sign签名已过期"),

    ERROR("0499","服务器异常,请稍后重试。如有问题,请联系管理员"),
    CUSTOM("0500","自定义异常");

    private String status;
    private String message;

    StatusEnum(String status, String message) {
        this.status = status;
        this.message = message;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

/**
 * @Description:  加密算法工具类
 * @Author: 臧东运
 * @CreateTime: 2019/4/22 14:10
 */
public class SecuritySHATool {
    public static final String KEY_SHA = "SHA";
    public static final String KEY_MD5 = "MD5";


    /**
     * MD5加密字节
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data) throws Exception {
        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);
        return md5.digest();

    }

    /**
     * SHA加密字节
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
        sha.update(data);
        return sha.digest();
    }


    /**
     * SHA加密
     *
     * @param inputStr
     * @return
     */
    public static String shaEncrypt(String inputStr) {
        byte[] inputData = inputStr.getBytes();
        String returnString = "";
        try {
            inputData = encryptSHA(inputData);
            for (int i = 0; i < inputData.length; i++) {
                returnString += byteToHexString(inputData[i]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnString;
    }


    private static String byteToHexString(byte ib) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
                'b', 'c', 'd', 'e', 'f'};
        char[] ob = new char[2];
        ob[0] = Digit[(ib >>> 4) & 0X0F];
        ob[1] = Digit[ib & 0X0F];
        String s = new String(ob);
        return s;
    }

    /**
     * MD5加密
     *
     * @param inputStr
     * @return
     */
    public static String md5Encrypt(String inputStr) {
        byte[] inputData = inputStr.getBytes();
        String returnString = "";
        try {
            BigInteger md5 = new BigInteger(encryptMD5(inputData));
            returnString = md5.toString(16);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return returnString;
    }

    public static String dataDecrypt(Map<String, Object> serviceParams) {
        StringBuilder sb = new StringBuilder();
        Object[] keys = serviceParams.keySet().toArray();
        Arrays.sort(keys);
        for (Object key : keys) {
            sb.append(key).append(serviceParams.get(key));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        System.out.println(shaEncrypt("username111password111"));
        System.out.println(md5Encrypt("111"));
    }

如果发现什么问题请留言,毕竟代码都是人写的难免会出错。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值