hessian-添加安全机制

Hessian和Burlap是caucho公司提供的开源协议,基于HTTP传输,服务端不用开防火墙端口。协议的规范公开,可以用于任意语言。
相比于常用的RPC协议WebService来说,hessian更加简单高效,速度更快,只需要简单的配置即可,无需生成任何类。相对于RMI
来说,hessian支持多种语言和平台,速度也不逊于前者。相对于ICE,hessian是基于http协议,可以穿透防火墙,无需配置相关
设置。因为它是一个Servlet,底层性的工作,比如 输入输出流、并发、日志等事情都可以交给Tomcat、Resin,也便于横向扩容。

不过在使用中发现hessian框架本身也有自己的劣势,比如缺乏安全机制,缺乏超时设置等等。在pop订单中心搭建的过程中,
也参考了网上一些解决方案,在hessian和spring原有的类上面做了扩展,加入了token验证,客户端超时时间配置和最大线程数
限制。配置方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
<bean id="offlineOrderServiceClient"
          class="com.tmaic.util.MyHessianProxyFactoryBean">
        <property name="serviceUrl"
                  value="http://127.0.0.1/hessian/helloHessian"/>
        <property name="serviceInterface"
                  value="com.tmaic.service.ShareWordService"/>
        <property name="overloadEnabled" value="true"/>
        <property name="connectTimeOut" value="30000"/>
        <property name="readTimeOut" value="30000"/>
        <property name="poolMaxSize" value="30"/>
        <property name="token" value="123456"/>
    </bean>

MyHessianProxyFactoryBean 类是继承自HessianProxyFactoryBean,通过spring注入可以方便的
在接入hessian接口时候根据自身接口的需求动态配置参数,connectTimeOut和readTimeOut 限制了最大
超时时间,poolMaxSize 限制了该客户端最大的线程数,token 则是对客户端的安全校验密钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class MyHessianProxyFactoryBean extends HessianProxyFactoryBean{
    private int readTimeOut = 500;
    private int connectTimeOut = 30000;
    private int poolMaxSize = 20;
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private AtomicInteger invokeCount = new AtomicInteger(0);
    private String token;

    public int getReadTimeOut() {
        return readTimeOut;
    }

    public void setReadTimeOut(int readTimeOut) {
        this.readTimeOut = readTimeOut;
    }

    public int getConnectTimeOut() {
        return connectTimeOut;
    }

    public void setConnectTimeOut(int connectTimeOut) {
        this.connectTimeOut = connectTimeOut;
    }

    public int getPoolMaxSize() {
        return poolMaxSize;
    }

    public void setPoolMaxSize(int poolMaxSize) {
        this.poolMaxSize = poolMaxSize;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public void prepare() throws RemoteLookupFailureException {
        MyHessianProxyFactory proxyFactory = new MyHessianProxyFactory();
        if(this.readTimeOut >0){
            proxyFactory.setReadTimeOut(this.readTimeOut);
        }
        if(this.connectTimeOut >0){
            proxyFactory.setConnectTimeOut(this.connectTimeOut);
        }
        if(StringUtils.isNotBlank(token)){
            proxyFactory.setToken(token);
        }
        this.setProxyFactory(proxyFactory);

        super.prepare();
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        this.lock.lock();
        try{
            if(invokeCount.get() > this.poolMaxSize){
                System.out.println("invokeCount:"+invokeCount.get());
                condition.await(this.readTimeOut, TimeUnit.MILLISECONDS);
            }
            if (invokeCount.get() > this.poolMaxSize) {
                 throw new IOException("wait hessian pool timeout: poolSize:" +
                         this.poolMaxSize + ", timeout:" + this.readTimeOut +", no="+invokeCount.get());
            }
            this.invokeCount.incrementAndGet();

        }finally {
            this.lock.unlock();
        }

        Object o = null;
        try{
            o=super.invoke(invocation);
        }finally {
            this.lock.lock();

            try{
                this.invokeCount.decrementAndGet();
                condition.signal();
            }finally {
                this.lock.unlock();
            }
        }

        return o;
    }
}

MyHessianProxyFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class MyHessianProxyFactory extends HessianProxyFactory{
    private int connectTimeOut = 30000;
    private int readTimeOut = 30000;
    private String token;

    public int getConnectTimeOut() {
        return connectTimeOut;
    }

    public void setConnectTimeOut(int connectTimeOut) {
        this.connectTimeOut = connectTimeOut;
    }

    public int getReadTimeOut() {
        return readTimeOut;
    }

    public void setReadTimeOut(int readTimeOut) {
        this.readTimeOut = readTimeOut;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

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

        if (this.connectTimeOut > 0) {
            conn.setConnectTimeout(this.connectTimeOut);
        }
        if (this.readTimeOut > 0) {
            conn.setReadTimeout(this.readTimeOut);
        }
        if(token!=null && !"".equals(token)){
            conn.setRequestProperty("AUTH",token);
        }
        return conn;
    }
}

MyHessianServiceExporter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MyHessianServiceExporter extends HessianServiceExporter{
    private String token;
    private final static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MyHessianServiceExporter.class);

    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String auth = request.getHeader("AUTH");

        if(!checkTokenHeader(auth)){
            logger.error("token is error!");
            return;
        }
        super.handleRequest(request, response);
    }

    private boolean checkTokenHeader(String clientToken){
        if (StringUtils.isBlank(clientToken)) {
            return false;
        }
        if (StringUtils.isBlank(token)) {
            return false;
        }
        return token.equals(clientToken);
    }
    //get set
    public void setToken(String token) {
        this.token = token;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值