PRC 技术实现:Hessian 基于DSA算法实现对时间戳签名验证

        当今RPC的相关技术实现比较多,比如:Spring HttpInvoker,Hessian,Apache Thrift,Google Protobuf等。。。以上技术实现对比网上有很多,这里主要介绍一下Hessian(http://hessian.caucho.com/)的安全验证的一种实现方案,hessian本身支持基于app server的用户名+密码验证,本文更进一步,基于DSA算法,实现对时间戳签名验证:

1.密钥对生成类,生成公钥和私钥

public class keyGenerator {
	private static KeyPairGenerator kpg = null;
	private static KeyPair kp = null;
	private static PublicKey public_key = null;
	private static PrivateKey private_key = null;
	private static FileOutputStream public_file_out = null;
	private static ObjectOutputStream public_object_out = null;
	private static FileOutputStream private_file_out = null;
	private static ObjectOutputStream private_object_out = null;

	public static void main(String[] args) {
		try {

			kpg = KeyPairGenerator.getInstance("DSA"); // 创建‘密匙对’生成器
			kpg.initialize(1024); // 指定密匙长度(取值范围:512~2048)
			kp = kpg.genKeyPair(); // 生成‘密匙对’,其中包含着一个公匙和一个私匙的信息
			public_key = kp.getPublic(); // 获得公匙
			private_key = kp.getPrivate(); // 获得私匙
			// 保存公匙
			public_file_out = new FileOutputStream("d:" + "/public_key.dat");
			public_object_out = new ObjectOutputStream(public_file_out);
			public_object_out.writeObject(public_key);
			// 保存私匙
			private_file_out = new FileOutputStream("d:" + "/private_key.dat");

			private_object_out = new ObjectOutputStream(private_file_out);
			private_object_out.writeObject(private_key);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

2.签名实现类,负责加签和验签

public class SimpleSignatureService implements SignatureService {
	protected Logger log = LoggerFactory.getLogger(getClass());

	private String algonrithm = "DSA";
	private PublicKey publicKey;
	private PrivateKey privateKey;

	/**
	 * 签名
	 */
	@Override
	public String sign(String content) throws Exception {
		try {
			Signature signature = Signature.getInstance(algonrithm);
			signature.initSign(privateKey);
			signature.update(content.getBytes());
			byte[] result = signature.sign();
			return EncodeUtils.hexEncode(result);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
	}

	/**
	 * 验签
	 */
	@Override
	public boolean verify(String signature, String content) throws Exception {
		try {
			Signature verifyalg = Signature.getInstance(algonrithm);
			verifyalg.initVerify(publicKey);
			verifyalg.update(content.getBytes());
			return verifyalg.verify(EncodeUtils.hexDecode(signature));
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
	}

	public void setPrivateKey(Resource privateKeyResource) throws Exception {
		try {
			ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(privateKeyResource.getFile()));
			privateKey = (PrivateKey) keyIn.readObject();
			keyIn.close();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
	}

	public void setPublicKey(Resource publicKeyResource) throws Exception {
		try {
			ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(publicKeyResource.getFile()));
			publicKey = (PublicKey) keyIn.readObject();
			keyIn.close();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
	}
}

3.Hessian服务导出实现类(服务端使用)

public class SecurityHessianServiceExporter extends HessianServiceExporter {
	protected Logger log = LoggerFactory.getLogger(getClass());
	private SignatureService signatureService;
	private long expireTime;//timestamp有效期(毫秒)
	private String token;

	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Assert.notNull(token, "Token 不允许为空!");
		String signature = request.getHeader("_TShark_Signature");
		String timestamp = request.getHeader("_TShark_Timestamp");
		if (StringUtil.isEmpty(signature)) {
			log.error("Signature is empty!");
			throw new ServletException("Signature is empty!");
		}
		if (StringUtil.isEmpty(timestamp)) {
			log.error("Timestamp is empty!");
			throw new ServletException("Timestamp is empty!");
		}
		if (expireTime > 0) {
			long now = new Date().getTime();
			long range = now - Long.parseLong(timestamp);
			if (range < 0) {
				range = -range;
			}
			if (range > expireTime) {
				log.error("Timestamp is timeout");
				throw new ServletException("Timestamp is timeout");
			}
		}

		try {
			if (signatureService.verify(signature, timestamp + "#" + token)) {
				super.handleRequest(request, response);
			} else {
				log.error("Signature is invalid!");
				throw new ServletException("Signature is invalid!");
			}
		} catch (Exception e) {
			log.error("Failed to process remote request!", e);
			throw new ServletException(e);
		}
	}

	public SignatureService getSignatureService() {
		return signatureService;
	}

	public void setSignatureService(SignatureService signatureService) {
		this.signatureService = signatureService;
	}

	public long getExpireTime() {
		return expireTime;
	}

	public void setExpireTime(long expireTime) {
		this.expireTime = expireTime;
	}

	public String getToken() {
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}
}
4.Hessian代理工厂类(客户端使用)

public class SecurityHessianProxyFactory extends HessianProxyFactory {
	protected Logger log = LoggerFactory.getLogger(getClass());
	private SignatureService signatureService;
	private int connectTimeout = 0;
	private String token;

	public URLConnection openConnection(URL url) throws IOException {
		URLConnection conn = super.openConnection(url);

		if (connectTimeout > 0) {
			conn.setConnectTimeout(connectTimeout);
		}
		long timestamp = new Date().getTime();
		//对timestamp进行签名
		conn.setRequestProperty("_TShark_Signature", createSignatureByTimestamp(timestamp));
		conn.setRequestProperty("_TShark_Timestamp", Long.toString(timestamp));
		return conn;
	}

	private String createSignatureByTimestamp(long timestamp) {
		try {
			return signatureService.sign(timestamp + "#" + token);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new TSharkException(e);
		}
	}

	public SignatureService getSignatureService() {
		return signatureService;
	}

	public void setSignatureService(SignatureService signatureService) {
		this.signatureService = signatureService;
	}

	public int getConnectTimeout() {
		return connectTimeout;
	}

	public void setConnectTimeout(int connectTimeout) {
		this.connectTimeout = connectTimeout;
	}

	public String getToken() {
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}
}
5.服务端配置文件applicationContext-remote.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
	default-lazy-init="true">

	<bean id="xxxService" class="org.tshark.core.remote.http.SecurityHessianProxyFactoryBean">
		<property name="serviceUrl"	value="http://xxx.xxx.xxx.xxx/XxxxServiceImpl" />
		<property name="serviceInterface" value="xxx.XxxxService" />
		<property name="proxyFactory" ref="hessianProxyFactory" />
	</bean>

	<bean id="hessianProxyFactory" class="org.tshark.core.remote.http.SecurityHessianProxyFactory">
		<property name="connectTimeout" value="10000" />
		<property name="token" value="tshark-2012" />
		<property name="signatureService" ref="simpleSignatureService" />
	</bean>

	<bean id="simpleSignatureService" class="org.tshark.core.security.impl.SimpleSignatureService">
		<property name="publicKey" value="classpath:public_key.dat" />
		<property name="privateKey" value="classpath:private_key.dat" />
	</bean>

</beans>

在web.xml中增加:

   	<!--Hessian-->
	<servlet>
		<servlet-name>remote</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:applicationContext-remote.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
    <servlet-mapping>
		<servlet-name>remote</servlet-name>
		<url-pattern>/remote/*</url-pattern>
	</servlet-mapping>



6.客户端配置文件applicationContext-client.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
	default-lazy-init="true">

	<bean name="/XxxxService"	class="org.tshark.core.remote.http.SecurityHessianServiceExporter">
		<property name="service" ref="xxxService" />
		<property name="serviceInterface" value="xxx.XxxxService" />
		<property name="signatureService" ref="simpleSignatureService" />
		<property name="token" value="tshark-security-2012" /><!--需要与服务端配置一致-->
	</bean>

	<bean id="simpleSignatureService" class="org.tshark.core.security.impl.SimpleSignatureService">
		<property name="publicKey" value="classpath:public_key.dat" />
		<property name="privateKey" value="classpath:private_key.dat" />
	</bean>
</beans>
7.客户端注入: xxxService类,调用其中方法即可






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值