java实现后端接口加密

思想:先给大家讲讲我们如何来实现接口加密,我们主要通过签名验证的方式来实现接口加密,前端给后端接口传参数时

           先用aes加密,生成一个sign签名,后端写一个拦截器对其进行签名验证,后端接收到参数后,也通过同样的方法

           对其参数加密生成一个sign,两者相对比,如何相同则签名成功! 自己在加密生成签名时,自己也可以定义一系列规则

           ,比如,我这里在加密前先对其进行排序后进行加密。


代码如下:


html代码


<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE>
<html>
<head>
    <base href="<%=basePath%>">
    <title>接口验证</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">

    <meta name="viewport" content="width=device-width, initial-scale=1.0,  maximum-scale=1.0, user-scalable=no">
    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
    <script src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
    <script src="${pageContext.request.contextPath}/js/crypto-js.js"></script>
    <script src="${pageContext.request.contextPath}/js/aes.js"></script>
    <script src="${pageContext.request.contextPath}/js/mode-ecb.js"></script>
    <script src="${pageContext.request.contextPath}/js/verify.js"></script>
    <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>

</head>

<body>
<div class="container">
    <div class="row">
        <form class="form-horizontal" role="form" id="form">
            <div class="form-group">
                <label for="firstname" class="col-sm-2 control-label">名字</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" name="name" id="firstname" placeholder="请输入名字">
                </div>
            </div>
            <div class="form-group">
                <label for="sex" class="col-sm-2 control-label">性别</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" name="sex" id="sex" placeholder="请输入名字">
                </div>
            </div>
            <div class="form-group">
                <label for="age" class="col-sm-2 control-label">年龄</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" name="age" id="age" placeholder="请输入名字">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <button type="button" οnclick="dl()" class="btn btn-default">登录</button>
                </div>
            </div>
        </form>
    </div>
</div>
</body>
</html>
<script>
    

js代码:

var map = {};
// function Encrypt(word){ //加密
//     var key = CryptoJS.enc.Utf8.parse("abcdefgabcdefg12");
//     //console.log("key:" + key);
//     var srcs = CryptoJS.enc.Utf8.parse(word);
//     //console.log("srcs:" + srcs);
//     var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
//     return encrypted.toString();
// }
// function Decrypt(word){  //解密
//     var key = CryptoJS.enc.Utf8.parse("abcdefgabcdefg12");
//
//     var decrypt = CryptoJS.AES.decrypt(word, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
//     return CryptoJS.enc.Utf8.stringify(decrypt).toString();
// }

 * 以上注释代码为加密和解密代码,这个我们是不能暴露在网页上面的,如果暴露在上面
   别人知道你的key值后就可以对你的加密结果进行解密了,目前就只找到通过js混淆来解决,
   以下一行就是上面注释代码通过混淆后的代码

function Encrypt(ZWeAf1){    var M2 = CryptoJS["\x65\x6e\x63"]["\x55\x74\x66\x38"]["\x70\x61\x72\x73\x65"]("\x61\x62\x63\x64\x65\x66\x67\x61\x62\x63\x64\x65\x66\x67\x31\x32");    var JMCt_3 = CryptoJS["\x65\x6e\x63"]["\x55\x74\x66\x38"]["\x70\x61\x72\x73\x65"](ZWeAf1);    var fQihKY4 = CryptoJS["\x41\x45\x53"]["\x65\x6e\x63\x72\x79\x70\x74"](JMCt_3, M2, {mode:CryptoJS["\x6d\x6f\x64\x65"]["\x45\x43\x42"],padding: CryptoJS["\x70\x61\x64"]["\x50\x6b\x63\x73\x37"]});    return fQihKY4["\x74\x6f\x53\x74\x72\x69\x6e\x67"]();}function Decrypt(GflP6){    var TpV7 = CryptoJS["\x65\x6e\x63"]["\x55\x74\x66\x38"]["\x70\x61\x72\x73\x65"]("\x61\x62\x63\x64\x65\x66\x67\x61\x62\x63\x64\x65\x66\x67\x31\x32");    var ksLf_V8 = CryptoJS["\x41\x45\x53"]["\x64\x65\x63\x72\x79\x70\x74"](GflP6, TpV7, {mode:CryptoJS["\x6d\x6f\x64\x65"]["\x45\x43\x42"],padding: CryptoJS["\x70\x61\x64"]["\x50\x6b\x63\x73\x37"]});    return CryptoJS["\x65\x6e\x63"]["\x55\x74\x66\x38"]["\x73\x74\x72\x69\x6e\x67\x69\x66\x79"](ksLf_V8)["\x74\x6f\x53\x74\x72\x69\x6e\x67"]();}

function dl(form) {
    var name = $("#firstname").val();
    var sex = $("#sex").val();
    var age = $("#age").val();
    map["name"] = name;
    map["age"] = age;
    map["sex"] = sex;
    map["xm-name"]="SSM";
    map["dev-name"]="spf";
    var arr2 = sortToMap();
    var str = sign(arr2)
    console.log(str);
    $.ajax({
       url:'/sign',
        type:'POST',
        data :{"name":name,"age":age,"sex":sex,"sign":str},
        dataType : 'json',
        success:function (res) {
           console.log(res);
            if (res.code == 200) {
                alert("签名成功");
            }
        }
    });
}

//对参数拼接成 XXX=XXX&XXX==XXXX 字符串的形式 后再进行加密
function sign(arr2) {
    var str = "";
    for (var i = 0; i < arr2.length; i++){
        if (map[arr2[i]] == null || map[arr2[i]] == "" || map[arr2[i]] == undefined) {
            continue;
        }
        str += arr2[i] + "=" + map[arr2[i]]+"&";
    }
    str = str.substring(0, str.length - 1);
    console.log(str);
    str = Encrypt(str);
    return str;
}
// 对参数排序
function sortToMap() {
    var arr=new Array()
    for(var key in map) {
        arr.push(key);
    }
    arr.sort();
    return arr;
}

后端代码


拦截器代码:

package com.utils.interceptor;

import com.controller.mail.MailController;
import com.utils.BaseUtils;
import com.utils.common.AES;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * Created by Administrator on 2017/6/16 0016.
 */
public class SignInterceptor implements HandlerInterceptor {

    private static final Logger logger = Logger.getLogger(MailController.class);

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        Map<String, Object> map = BaseUtils.getParamMap(request);
        Object osign = map.get("sign");
        if (osign == null) {
            return false;
        }
        map.put("xm-name","SSM");
        map.put("dev-name","spf");
        map.remove("sign");
        String str = BaseUtils.createLinkString(map);
        String key = "abcdefgabcdefg12";
        String sign = AES.encryptToBase64(str,key);

        if (!sign.equals(osign.toString())) {
            logger.info("===================>签名验证失败<========================");
            return false;
        }
        return true;
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}
 
用到的工具类代码
 
/**
 * 获取request 中的参数,以map形式返回
 * @param request
 * @return
 */
public static Map<String, Object> getParamMap(ServletRequest request) {
   //Assert.notNull(request,"参数不能为空");
   Map<String, Object> map = Maps.newHashMap();
   Enumeration<String> en = request.getParameterNames();
   while (en.hasMoreElements()) {
      String name = en.nextElement();
      String[] values = request.getParameterValues(name);
      if (values == null || values.length == 0) {
         continue;
      }
      String value = values[0];
      if (value != null) {
         map.put(name, value);
      }
   }
   return map;
}

/**
 * 把数组所有元素,按字母排序,然后按照“参数=参数值”的模式用“&”字符拼接成字符串
 *
 * @param params
 *            需要签名的参数
 * @return 签名的字符串
 */
public static String createLinkString(Map<String, Object> params) {
   List<String> keys = Lists.newArrayList(params.keySet().iterator());
   Collections.sort(keys);
   StringBuilder signStr = new StringBuilder();
   for (String key : keys) {
      if (!checkNotNull(params.get(key).toString())) {
         continue;
      }
      signStr.append(key).append("=").append(params.get(key)).append("&");
   }
   return signStr.deleteCharAt(signStr.length() - 1).toString();
}
/**
*加密
*/

public static String encryptToBase64(String data, String key){
     try {
         byte[] valueByte = encrypt(data.getBytes(CHAR_ENCODING), key.getBytes(CHAR_ENCODING));
         return new String(Base64.encodeBase64(valueByte,false));
     } catch (UnsupportedEncodingException e) {
         throw new RuntimeException("encrypt fail!", e);
     }

 }

现在就来运行查看一下结果吧:

1.启动项目




点击登录:查看结果



这里我们在拦截器里就可以看见签名了,1 表示前端传过来的签名,2表示后端签名,签名相同就返回true,进入action,不相同就返回false,请求中断


参看结果



成功! 


我这里写的测试代码,比较草率,建议大家把 js 加密,排序,组装为字符串等一些列代码提出来写在一个 js 文件里,然后在通过 js 混淆处理,

把混淆后的代码复制粘贴进去,把原来代码删除!


觉得有用请点个赞,谢谢!




  • 12
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
编写Java后端接口设计文档是为了确保接口的设计和实现符合预期的需求,同时方便团队成员共同合作开发。以下是编写Java后端接口设计文档的一般步骤和内容: 1. 引言:介绍文档的目的和范围,描述接口设计的背景和重要性。 2. 需求分析:列出接口的功能需求和业务需求,明确接口需要实现的具体功能和效果。 3. 接口概述:对接口进行总体概述,包括接口的名称、版本号、作者、创建日期等基本信息。 4. 接口设计原则:阐述接口设计的原则和准则,例如高内聚、低耦合、易于扩展等。 5. 接口列表:列出所有接口的名称、URL路径、请求方法(GET、POST等)、参数和返回值的数据类型等详细信息。 6. 请求参数:对每个接口的请求参数进行详细描述,包括参数名称、类型、是否必选、默认值、说明等。 7. 返回结果:定义每个接口的返回结果,包括数据结构和字段含义,可以使用JSON示例来演示返回结果的格式。 8. 错误码及异常处理:定义可能出现的错误码和异常情况,包括错误码的含义和建议的处理方式。 9. 接口调用示例:给出几个常用接口的请求示例,包括接口的URL、请求方法、请求参数和返回结果等。 10. 接口安全:描述接口的安全措施,如权限验证、数据加密等。 11. 接口性能优化:提供接口的性能优化建议,如缓存使用、并发处理等。 12. 接口变更记录:记录接口的变更历史,包括版本号、变更内容和修改时间等。 13. 参考资料:列出参考的文档或网址,方便后续查询和开发者理解文档中的相关知识。 14. 附录:补充一些必要的辅助信息,如术语解释、约定规范等。 编写Java后端接口设计文档需要考虑文档的清晰性、完整性和易读性。接口设计文档应该与接口代码同步更新,随着项目的演化和需求的变化,及时进行维护和更新。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值