分析
使用签名的机制通过拦截器实现防篡改(避免请求中途被黑客修改了请求参数值而请求接口) 前端用和后端一样的算法,将请求参数通过算法生成一个sign 后端用和前端一样的算法,也传过来的参数算法生成一个sign 比对前端和后端的sign是否一致,若不一致则是请求中途中被篡改过,则此次访问接口请求将会报错
前端部分
请求函数
ajaxGet ( "/test2" , { a: 1 , b: 2 , c: 3 , d: 4 } , function ( data) {
console. log ( data) ;
} )
function ajaxGet ( url, params, success, fail) {
ajaxRequest ( url, "GET" , params, success, fail) ;
}
function ajaxRequest ( url, type, param, success, fail) {
param. sign = getSignString ( param) ;
var token = getToken ( ) ;
$. ajax ( {
type: type,
url: domainUrl + url,
data: param,
dataType: 'json' ,
beforeSend: function ( xhr) {
xhr. setRequestHeader ( "token" , token) ;
} ,
success: function ( data) {
if ( ! data) {
popup ( "请求异常" ) ;
} else {
if ( data. code == 200 ) {
if ( success) {
success ( data) ;
}
} else if ( data. code == 401 ) {
Cookies. remove ( "token" ) ;
Cookies. remove ( "user" ) ;
$( ".login-out" ) . css ( "display" , "" )
$( ".login_info" ) . css ( "display" , "none" )
popup ( "请先登录" ) ;
} else {
if ( fail) {
fail ( data) ;
} else {
popup ( data. msg) ;
}
}
}
} ,
error: function ( ) {
popup ( "网络不通,请联系管理员~" ) ;
}
} )
}
算法函数(重点)
引入md5.js文件,即可使用md5加密,可通过我博客资源下寻找并下载此js文件 getSignString函数 将要请求的参数拼接起来(如:a=1&b=2&c=3&d=4
),然后通过MD5加密生成sign
function getSignString ( param) {
var sdic= Object. keys ( param) . sort ( ) ;
var signStr = "" ;
for ( var i in sdic) {
if ( i == 0 ) {
signStr += sdic[ i] + "=" + param[ sdic[ i] ] ;
} else {
signStr += "&" + sdic[ i] + "=" + param[ sdic[ i] ] ;
}
}
console. log ( signStr) ;
console. log ( hex_md5 ( signStr) ) ;
return hex_md5 ( signStr) . toUpperCase ( ) ;
}
后端部分
MD5工具类
public class Md5Utils {
public static String getMD5 ( String message) {
String md5 = "" ;
try {
MessageDigest md = MessageDigest. getInstance ( "MD5" ) ;
byte [ ] messageByte = message. getBytes ( "UTF-8" ) ;
byte [ ] md5Byte = md. digest ( messageByte) ;
md5 = bytesToHex ( md5Byte) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
return md5;
}
private static String bytesToHex ( byte [ ] bytes) {
StringBuffer hexStr = new StringBuffer ( ) ;
int num;
for ( int i = 0 ; i < bytes. length; i++ ) {
num = bytes[ i] ;
if ( num < 0 ) {
num += 256 ;
}
if ( num < 16 ) {
hexStr. append ( "0" ) ;
}
hexStr. append ( Integer. toHexString ( num) ) ;
}
return hexStr. toString ( ) . toUpperCase ( ) ;
}
public static String signatures ( Map< String, Object> params) {
String signatures = "" ;
try {
List< String> paramsStr = new ArrayList < String> ( ) ;
for ( String key1 : params. keySet ( ) ) {
if ( null != key1 && ! "" . equals ( key1) ) {
paramsStr. add ( key1) ;
}
}
Collections. sort ( paramsStr) ;
StringBuilder sbff = new StringBuilder ( ) ;
for ( String kk : paramsStr) {
String value = params. get ( kk) . toString ( ) ;
if ( "" . equals ( sbff. toString ( ) ) ) {
sbff. append ( kk + "=" + value) ;
} else {
sbff. append ( "&" + kk + "=" + value) ;
}
}
signatures = getMD5 ( sbff. toString ( ) ) . toUpperCase ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
return signatures;
}
}
定义拦截器
public class SignInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if ( ! ( handler instanceof HandlerMethod ) ) {
return true ;
}
Map< String, String[ ] > map = request. getParameterMap ( ) ;
Map< String, Object> param = new HashMap < > ( ) ;
for ( String s : map. keySet ( ) ) {
if ( "sign" . equalsIgnoreCase ( s) ) {
continue ;
}
param. put ( s, arrayToString ( map. get ( s) ) ) ;
}
String signatures = Md5Utils. signatures ( param) ;
String sign = request. getParameter ( "sign" ) ;
if ( sign == null || ! sign. equalsIgnoreCase ( signatures) ) {
response. setContentType ( "text/json;charset=UTF-8" ) ;
response. getWriter ( ) . write ( JSON. toJSONString ( new JsonResult ( 501 , "签名校验失败" , "不好意思咯" ) ) ) ;
return false ;
}
return true ;
}
private String arrayToString ( String [ ] array) {
StringBuilder sb = new StringBuilder ( 10 ) ;
for ( String s : array) {
sb. append ( s) ;
}
return sb. toString ( ) ;
}
}
测试接口
@RestController
public class TestController {
@GetMapping ( "/test2" )
public Object test2 ( int a, int b, int c, int d, String sign) {
return JsonResult. success ( Arrays. asList ( a, b, c, d, sign) ) ;
}
}
效果演示
成功
失败
我把成功的签名值不变,改变了参数值然后请求,则报错~