栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot使用拦截器拦截验证签名sign

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springboot使用拦截器拦截验证签名sign

1生成签名 2使用拦截器验证签名 2.1重写request,以读取存储二级制流 2.2配置过滤器,将默认的request替换为重写的 2.3配置过滤器 2.4写拦截器 2.5配置拦截器 1生成签名
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.renren.common.utils.SM3Util;
import cn.hutool.core.util.HexUtil;

import java.util.HashMap;
import java.util.Map;

public class SignUtils {
    public static void main(String[] args) {
    //appid对应一个accessKey,存储在数据库中
        String accessKey = "71a8e08ca1122c61faff1abffcbc8226b9a2e940";
        Long timestamp = System.currentTimeMillis();
        Map map = new HashMap();
        map.put("id","333");
        map.put("id2","陈大壮");
        map.put("passwd","XFCY8R7dhRRnyXDMAlzTNvDKnf9zT2RO1bVc8LXe0K6Qj6vifnWawy5JJw6vhl8xuokTQPqTtoK8gpKfslS08emERiejbZrhrYfmyeof7EPpv+VCwLQ/vbbi4hwwUtK+9s8M6MuOXVAisd06WXq5BdT4RDMDvd48pptB+tXJsd8=");

        ObjectMapper objectMapper = new ObjectMapper();
        String hexStr = "";
        try {
            String valueAsString = objectMapper.writeValueAsString(map);
            System.out.println(valueAsString);
            String verifySing = accessKey + "&" + timestamp + "&" + valueAsString;
            System.out.println(verifySing);
            byte[] hmac = SM3Util.hash(verifySing.getBytes());
            hexStr = HexUtil.encodeHexStr(hmac);
            System.out.println(hexStr);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

生成json串类似下图。

{
   "timeStamp":"1650606559147",
   "sign":"3cb7c8b5715e510de106b76c40e1397a5d5c73c70d53994f3eca3b72c84a8264",
   "appId":"fxIzd7xG",
   "data":{
       "id2":"陈大壮",
       "id":"333",
       "passwd":"XFCY8R7dhRRnyXDMAlzTNvDKnf9zT2RO1bVc8LXe0K6Qj6vifnWawy5JJw6vhl8xuokTQPqTtoK8gpKfslS08emERiejbZrhrYfmyeof7EPpv+VCwLQ/vbbi4hwwUtK+9s8M6MuOXVAisd06WXq5BdT4RDMDvd48pptB+tXJsd8="
   }
}
2 使用拦截器验证签名 2.1重写request,以读取存储二级制流
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;


import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;


@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {

    
    private final byte[] body;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);

        // 将body数据存储起来
        body = getBodyString(request).getBytes(Charset.defaultCharset());
    }

    
    public String getBodyString(final ServletRequest request) {
        try {
            return inputStream2String(request.getInputStream());
        } catch (IOException e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
    }

    
    public String getBodyString() {
        final InputStream inputStream = new ByteArrayInputStream(body);

        return inputStream2String(inputStream);
    }

    
    private String inputStream2String(InputStream inputStream) {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("", e);
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    log.error("", e);
                }
            }
        }

        return sb.toString();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);

        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return inputStream.read();
            }

            @Override
            public boolean isFinished() {
                return true;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

}

2.2配置过滤器,将默认的request替换为重写的
import io.renren.modules.sys.request.RequestWrapper;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Slf4j
public class ReplaceStreamFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);
        chain.doFilter(requestWrapper, response);
    }
}

2.3配置过滤器
import io.renren.common.xss.XssFilter;
import io.renren.modules.sys.filter.ReplaceStreamFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;


@Configuration
public class FilterConfig {




    
    @Bean
    public FilterRegistrationBean someFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new ReplaceStreamFilter());
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.addUrlPatterns("/api
public class SignInterceptor implements  HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private SystemProperties systemProperties;
    @Autowired
    private AccessService accessService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");

        RequestWrapper requestWrapper = new RequestWrapper(request);
        String jsonParam = requestWrapper.getBodyString();

        JSONObject json = (JSONObject) JSONObject.parseObject(jsonParam);

        logger.info("[ACCESS LOG] body args:" + (json == null ? "" : json.toJSONString()));
        String appId = json.getString("appId");
        String sign = json.getString("sign");
        String timeStamp = json.getString("timeStamp");
        String data = json.getString("data");
        logger.info("开始验证签名"+sign);
        if(StringUtils.isEmpty(sign)||StringUtils.isEmpty(appId)){
            PrintWriter out = response.getWriter();
            out.print(JSON.toJSONString((R.error("sign或者appId为空"))));
            return false;
        }
        //验证时间戳是否在规定时间返回之内
        if(!TimeUtil.validTime(timeStamp,systemProperties.getIntervalTime())){
            PrintWriter out = response.getWriter();
            out.print(JSON.toJSONString((R.error("时间戳失效"))));
            return false;
        }
        //根据参数重新生成sign并验证,从数据库中appId获取数据accessKey
        AccessEntity accessEntity = accessService.queryAccessEntityByAppId(appId);
        String verifySing = accessEntity.getAppSecret() + "&" + timeStamp + "&" + data;
        //根据accessKey、时间错、数据验证签名是否有效
        boolean signFlag = SM3Util.verify(verifySing, sign);
        if(!signFlag){
            PrintWriter out = response.getWriter();
            out.print(JSON.toJSONString((R.error("签名错误"))));
            return false;
        }
        //todo判断是否有权限、是否白名单、是否禁用。
        logger.info("验证签名完成");
        return true;
    }



}

返回R类

import java.util.HashMap;
import java.util.Map;


public class R extends HashMap {
	private static final long serialVersionUID = 1L;
	
	public R() {
		put("code", 0);
		put("msg", "success");
	}
	
	public static R error() {
		return error(500, "未知异常,请联系管理员");
	}
	
	public static R error(String msg) {
		return error(500, msg);
	}
	
	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}
	
	public static R ok(Map map) {
		R r = new R();
		r.putAll(map);
		return r;
	}
	
	public static R ok() {
		return new R();
	}

	@Override
	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}

系统属性配置类


@Component
@ConfigurationProperties(prefix = "systemproperties")
@Data
public class SystemProperties {
    
    private int intervalTime;
    
    private String publicKey;
    
    private String secretKey;
    
    private String hostIp;



}

application.yml
时间戳的有效时间

systemproperties:
  intervalTime: 30

时间工具类

public class TimeUtil {
    
    public static boolean validTime(String timeStamp,int intervalTime){
       long timeStampL = Long.parseLong(timeStamp);
        return validTime(timeStampL,intervalTime);
    }
    
    public static boolean validTime(long timeStamp,int intervalTime){
        long current = System.currentTimeMillis();
        //取绝对值,当前时间之内波动几分钟
        long interval = Math.abs(current-timeStamp);
        //转换为分钟
        if(interval/(1000*60)>intervalTime){
            return false;
        }
        return true;
    }
}

这行代码,大家自行发挥替换
AccessEntity accessEntity = accessService.queryAccessEntityByAppId(appId);

验签工具类

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class SM3Util {
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    public static boolean verify(String srcStr, String sm3HexString) {
        boolean flag = false;
        try {
            //使用指定的字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中
            byte[] srcData = srcStr.getBytes();
            //16进制 --> byte[]
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
            byte[] newHash = hash(srcData);
            //判断数组是否相等
            if (Arrays.equals(newHash, sm3Hash)) {
                flag = true;
            }
        } catch (Exception e) {

        }
        return flag;
    }

}

2.5配置拦截器
import io.renren.modules.sys.interceptor.SignInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class WebConfig implements WebMvcConfigurer {

  
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(signInterceptor()).addPathPatterns("/api
@RestController
@RequestMapping("/api")
public class ApiController  {
	@Autowired
	private SystemProperties systemProperties;
	
	
	@RequestMapping("/list")
	public R list(@RequestBody ApiRequest apiRequest){
		System.out.println("data = " + apiRequest);
		System.out.println("data = " + apiRequest.getSign());
		System.out.println("data = " + apiRequest.getTimeStamp());
		System.out.println("data = " + apiRequest);
		return R.ok("恭喜成功了");
	}


	
	
}

2.7请求方式

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/839129.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号