leftso 2209 0 2018-01-02 20:14:02

文章位置:左搜> 编程技术> 正文

引言

    前面写了一篇Spring boot RPC 框架 Hessian。讲解了spring boot整合hessian的基本使用。这里主要围绕上一篇讲解的内容进行扩展讲解,hessian通讯的验证/加密实现安全的RPC访问。

一.自定义一个HessianServiceExporter

    从上一篇博客Spring boot RPC 框架 Hessian中我们可以发现,hessian的server端是通过HessianServiceExporter发布hessian接口服务的。
    
目前hessian的server端项目结构图:
项目结构图
与上一篇对比,项目结构中多了一个类HessianServerProxyExporter。这个类主要是继承了HessianServiceExporter类并重写了handleRequest方法:
package net.xqlee.project;

import java.io.IOException;
import java.util.Base64;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.remoting.caucho.HessianServiceExporter;
import org.springframework.util.StringUtils;
import org.springframework.web.util.NestedServletException;

/**
 * 自定义hessian服务发布,可用于自定义验证服务
 * 
 * @author xqlee
 *
 */
public class HessianServerProxyExporter extends HessianServiceExporter {

	private static final Logger log = LoggerFactory.getLogger(HessianServerProxyExporter.class);

	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String authorization = request.getHeader("authorization");
		if (StringUtils.isEmpty(authorization)) {
			throw new NestedServletException("Auth Is Empty!");
		}
		log.info(authorization);
		String[] authArr = authorization.trim().split(" ");
		String auth = authArr[1];
		auth = new String(Base64.getDecoder().decode(auth));
		String[] namePwdArr = auth.split(":");
		String pwd = namePwdArr[1];
		// 验证密码
		if (!"123456".equals(pwd)) {
			throw new NestedServletException("Auth Fail!");
		}
		super.handleRequest(request, response);

	}

}
验证的核心代码就在重写的方法里面,这里只是简单的进行了密码的认证。

为了使验证生效,我们需要重写类DemoSpringbootRpcHessianApplication:
package net.xqlee.project;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.caucho.HessianServiceExporter;

import net.xqlee.project.service.HelloWorldService;

@SpringBootApplication
public class DemoSpringbootRpcHessianApplication {
	@Autowired
	private HelloWorldService helloWorldService;

	public static void main(String[] args) {
		SpringApplication.run(DemoSpringbootRpcHessianApplication.class, args);
	}

	// 发布服务
	@Bean(name = "/HelloWorldService")
	public HessianServiceExporter accountService() {
//		HessianServiceExporter exporter = new HessianServiceExporter();
		HessianServerProxyExporter exporter=new HessianServerProxyExporter();
		exporter.setService(helloWorldService);
		exporter.setServiceInterface(HelloWorldService.class);
		return exporter;
	}
}
可以看到只是进行了简单修改,使用我们自己定义的HessianServerProxyExporter 来发布hessian服务,而不是默认的HessianServiceExporter。

二.hessian客户端设置用户密码

客户端的项目结构图没变,如下:
项目结构图
客户端比之前只是在访问hessian接口的时候多设置了用户名和密码:
package net.xqlee.project;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.caucho.HessianProxyFactoryBean;

import net.xqlee.project.service.HelloWorldService;

@SpringBootApplication
public class DemoSpringbootRpcHessianClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoSpringbootRpcHessianClientApplication.class, args);
	}

	@Bean
	public HessianProxyFactoryBean helloClient() {
		HessianProxyFactoryBean factory = new HessianProxyFactoryBean();
		factory.setServiceUrl("http://localhost:8083/HelloWorldService");
		factory.setServiceInterface(HelloWorldService.class);
		factory.setPassword("123456");
		factory.setUsername("download");
		return factory;
	}

}
注意:HessianProxyFactoryBean中必须同时设置用户名和密码才能生效。

通过访问客户端的服务,通过断点到hessian的服务端HessianServerProxyExporter类,我们可以看到是如何传递用户名和密码参数的:
hessian传递认证信息
可以看到传递到服务端是通过HTTP协议的header传递的。并且传递的Basic认证头。这个头后面跟的字符串就是用户名:密码的Base64字符串,通过base64解密我们可以得到:
base64解密
用户名:密码已经显示出来。同样后面的判断也能实现我们的通讯验证。


提示:
实际使用中,传递的密码或者用户请通过其他非对称加密方式加密后传输,服务端进行解密更为安全。