前言

在公司很多接口项目中,都要会有一些签名认证,签名认证的目的很简单,就是为了保护接口,不让别人调用,可能很多初学者没有对签名认证的一个概念,我现在大致可以讲一下签名认证的概念。
如果你写的接口没有签名认证,那么无论是谁都可以进行调用,只要url路劲是对的就行了,参数也没有限制,那么这个时候,签名认证就出现了,sign也是会通过参数进行传递,sign的规则可以随便定义,我现在的规则是这样子的
url=http//xxx/xxx?username=1&pwd=2
那么在前台进行传迪的sign就要按顺序进行拼接参数
sign = MD5(“username=1&pwd=2”+secret); 这个secret叫做密钥,后端和前端要进行商量,可以是随便的一个字符串,但是一定不能泄露出去,不然你的签名就可以进行伪造了。
后端会写一个拦截器,来拦截你的请求,以同样的方式接受你的参数进行拼接然后加上密钥进行加密,跟你的sign进行比较,如果是一样的,那就是合格的请求。
ok,言归正传,还是要进行对jfinal框架进行签名验证的,其实主就是如何编写拦截器,当时个人也一直很纳闷,因为jfinal框架添加自定义拦截器是要实现com.jfinal.aop.Interceptor 这个接口的,但是只有public void intercept(Invocation invocation)这个方法,里面没有我们要的request,没有办法进行参数的接收统计呀,到后面发现一个文档里面有一个方法,可以得到request。
invocation.getController().getRequest() ,重点就在此方法,ok,下面就是我自定义的拦截器,验证签名拦截器。

package com.atuinfo.Interceptors;

import com.alibaba.fastjson.JSON;
import com.atuinfo.core.Result;
import com.atuinfo.core.ResultCode;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class SignInterceptor implements Interceptor {
    private final Logger logger = LoggerFactory.getLogger(SignInterceptor.class);


    @Override
    public void intercept(Invocation invocation) {

        HttpServletRequest request = invocation.getController().getRequest();//获得request

        boolean pass = validateSign(invocation.getController().getRequest());
        System.out.println(pass);
        if(!pass){
            logger.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}",
                    request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
            Result result = new Result();
            result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败");
            invocation.getController().renderJson(result);
        }
        //System.out.println("进行sign校验");
        else{
            invocation.invoke();
        }

    }
    /**
     * 一个简单的签名认证,规则:
     * 1. 将请求参数按ascii码排序
     * 2. 拼接为a=value&b=value...这样的字符串(不包含sign)
     * 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较
     */
    private boolean validateSign(HttpServletRequest request) {
        String requestSign = request.getParameter("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57
        if (StringUtils.isEmpty(requestSign)) {
            return false;
        }
        List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
        keys.remove("sign");//排除sign参数
        Collections.sort(keys);//排序

        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串
        }
        String linkString = sb.toString();
        linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);//去除最后一个'&'

        //获取密钥
        Prop p = PropKit.use("demo-config-dev.txt").appendIfExists("atuinfo-config-pro.txt");
        String secret = p.get("secret");//密钥

        String ls = linkString + secret;
        String sign = DigestUtils.md5DigestAsHex(ls.getBytes());//混合密钥md5
        System.out.println("sign:"+sign);
        return StringUtils.equals(sign, requestSign);//比较
    }

    /**
     * 获取ip地址的方法
     * @param request
     * @return
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 如果是多级代理,那么取第一个ip为客户端ip
        if (ip != null && ip.indexOf(",") != -1) {
            ip = ip.substring(0, ip.indexOf(",")).trim();
        }

        return ip;
    }


}

怎么起作用呢,肯定要添加到配置文件里面去呀

java接口加签验签sign java接口签名框架_java接口加签验签sign


ok这就配置成功了,我们来看看结果吧。

这是失败的例子

java接口加签验签sign java接口签名框架_java接口加签验签sign_02


这是成功的例子

java接口加签验签sign java接口签名框架_java接口加签验签sign_03