在上一篇中,讲了如何把hessian集成到spring中,以便为我们的web提供方便的接口支持。
在使用的时候,我就在想,接口暴露出来了。那么如果一旦接口被他人获知,进行恶意的调用,那么就大大不妥了。第一的反应是服务器端用一个用户名和密码作为一个调用的认证,客户端在调用的时候,必须提供一个合法的用户名和密码才可以使用服务器提供的接口服务,但是这样在调用的过程,还是有可能被拦截,从而获取到这个用户名和密码进行恶意共计,也称为replay共计。如何防止这个情况出现。我想到了token机制。
接着上一篇的例子,我在其中加入了token验证的机制。参考了微信的做法,写了一个简单的token机制
服务器端
package com.example.hessian;
public interface Isay {
//安全签名加密参数
public void setSinagure(String sinatrue);
public void setNonce(String nonce);
public void setTimestamp(String timestamp);
//业务方法
public Hello sayHello(String age,String name);
}
sinatrue:签名加密
nonce:随机数
timestamp:时间戳
package com.example.hessian;
import com.example.hessian.token.TokenUtil;
public class IsayImpl implements Isay {
private String signature;
private String nonce;
private String timestamp;
@Override
public Hello sayHello(String age,String name) {
if(TokenUtil.validateSignature(signature, timestamp, nonce)){
Hello hl=new Hello();
hl.setAge(age);
hl.setName(name);
return hl;
}else{
return null;
}
}
@Override
public void setSinagure(String sinature) {
this.signature=sinature;
}
@Override
public void setNonce(String nonce) {
this.nonce=nonce;
}
@Override
public void setTimestamp(String timestamp) {
this.timestamp=timestamp;
}
}
TokenUtil
package com.example.hessian.token;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import com.base.util.PropertyUtils;
public class TokenUtil {
//私钥
private static String app_token=PropertyUtils.get("app_token");
//时间戳时间设置不能超过某个时间,防止传输过程中signature窃取后的连续攻击,这个值也不能设置太小,因为可能存在网络缓慢或者不稳定
private static int time_out=3000;
public static String generateNonce(){
Random random = new Random(123456789);
String nonce=random.nextInt()+""+random.nextInt()+""+random.nextInt()+""+random.nextInt();
return nonce;
}
public static String generateTimestamp(){
return System.currentTimeMillis()+"";
}
/**
* 利用token,时间戳和随机数生成加密签名
* @return
*/
public static String generateSignature(String timestamp,String nonce){
String signature=sha1(app_token+timestamp+nonce);
return signature;
}
/**
* 利用token,时间戳和随机数生成加密签名
* @return
*/
public static String generateSignature(String timestamp,String nonce,String app_token){
String signature=sha1(app_token+timestamp+nonce);
return signature;
}
/**
* 验证请求的签名
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean validateSignature(String signature,String timestamp,String nonce){
long ctime=System.currentTimeMillis();
long ttime=Long.valueOf(timestamp);
if((ctime-ttime)<time_out){
if(signature.equals(generateSignature(timestamp,nonce,app_token))){
return true;
}else{
return false;
}
}else{
return false;
}
}
/**
* sha1算法
*
* @param text
* @return
*/
public static String sha1(String text) {
MessageDigest md = null;
String outStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(text.getBytes());
outStr = byteToString(digest);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return outStr;
}
private static String byteToString(byte[] digest) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
String tempStr = Integer.toHexString(digest[i] & 0xff);
if (tempStr.length() == 1) {
buf.append("0").append(tempStr);
} else {
buf.append(tempStr);
}
}
return buf.toString().toLowerCase();
}
}
app_token=G4TT9jG3Y3S3pK4rBMxuCHFgRdo56SQKpC8WKv_4-rIeJ0UwnOaN9t8DCoIyKgSDAVAIKdV2cveWZ--oOEvsoYGy1jBTicXWQCgq2SHdo-Y
客户端:
package com.example.hessian.client;
import java.net.MalformedURLException;
import com.caucho.hessian.client.HessianProxyFactory;
import com.example.hessian.Hello;
import com.example.hessian.Isay;
import com.example.hessian.token.TokenUtil;
public class HessianClient {
public static void main(String[] args) throws MalformedURLException {
//客户端调用
String url = "http://localhost:8080/example/hessian/helloHessian";
HessianProxyFactory factory = new HessianProxyFactory();
Isay api = (Isay) factory.create(Isay.class, url);
//加密签名
String nonce=TokenUtil.generateNonce();
String timestamp=TokenUtil.generateTimestamp();
api.setNonce(nonce);
api.setTimestamp(timestamp);
api.setSinagure(TokenUtil.generateSignature(timestamp, nonce));
//业务调用
Hello hello=api.sayHello("25","jacky");
//输出返回结果
System.out.println(hello.getAge());
System.out.println(hello.getName());
}
}
这样一个简单的token认证就完成了。目前demo的例子是基于struts2 作为控制层的。spring mvc中集成hessian,基本与struts2+spring集成hessian一样。