当今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>
<?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类,调用其中方法即可

9300

被折叠的 条评论
为什么被折叠?



