【发布时间】:2023-10-31 01:56:02
【问题描述】:
我将为 java RMI 实现一个安全层,使用动态代理机制。 我在 rmi 注册表中绑定了一些具有远程接口的类,现在我正在编写一个类 SecurityInvocationHandler,代码如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
/**
*
* @author andrew
* @param <T>
*/
public class SecurityInvocationHandler<T> extends SuperRemoteInterface implements InvocationHandler {
final T remoteInterface;
public static <T> T newInstance(final T obj, RMIClientSocketFactory rcsf, RMIServerSocketFactory rssf) throws RemoteException {
return (T) java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new SecurityInvocationHandler(obj, rcsf, rssf));
}
private SecurityInvocationHandler(T remoteInterface, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException {
super(csf, ssf);
this.remoteInterface = remoteInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoke method -> " + method.getName());
//TODO
return method.invoke(remoteInterface, args);
}
}
SuperRemoteInterface 是所有具有“Remote”接口的类的父类:
import java.rmi.RemoteException;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import Config.SysConfiguration;
import java.rmi.server.UnicastRemoteObject;
public class SuperRemoteInterface extends UnicastRemoteObject {
protected SysConfiguration conf;
protected SuperRemoteInterface() throws RemoteException {
super();
}
protected SuperRemoteInterface(RMIClientSocketFactory clientFactory, RMIServerSocketFactory serverFactory) throws RemoteException {
super(0, clientFactory, serverFactory);
}
}
在 Server RMI 的 main 中,我代理 Object 并在 rmiregistry 中绑定它:
import /****/
public class ServerRMI extends UnicastRemoteObject {
public ServerRMI() throws RemoteException {
}
/*...*/
public static void main(String[] args) {
/*.....*/
try {
//Registry r = LocateRegistry.getRegistry();
Registry r = LocateRegistry.createRegistry(port);
RMIClientSocketFactory clientFactory = new RMISSLClientSocketFactory();
RMIServerSocketFactory serverFactory = new RMISSLServerSocketFactory();
AInterface proxy = (AInterface)SecurityInvocationHandler.newInstance(new AObject(conf), clientFactory, serverFactory);
r.bind("AObject", proxy);
/* ..... */
} catch (Exception e) {
//e.printStackTrace();
System.exit(-1);
}
}
}
绑定没问题,但是在客户端查找“AObject”时,出现这个错误:
java.lang.ClassCastException: cannot assign instance of $Proxy80 to field java.lang.reflect.Proxy.h of type java.lang.reflect.InvocationHandler in instance of $Proxy79
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2039)
at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1212)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1952)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1870)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at java.rmi.Naming.lookup(Naming.java:84)
at login_web.GetRemoteInterface.getAInterface(GetRemoteInterface.java:35)
.....
客户端代码是:
public class GetRemoteInterface {
private static final String _port = ":nnnn";
private String hostAddress;
public GetRemoteInterface() throws UnknownHostException {
/*....*/
public AInterface getAInterface() throws MalformedURLException, RemoteException, NotBoundException{
return (AInterface) Naming.lookup("//"+hostAddress+_port+"/AObject");
}
}
没有代理机制查找ok,使用这些代码不起作用。 也许不可能用 java rmi 绑定代理对象??
提前致谢。
附:对不起我的英语
【问题讨论】:
-
我已经这样做了,所以这当然是可能的。但首先你需要重新考虑你的 API。它没有提供远程对象实现多个远程接口的情况。您可能会发现所需的重新设计很有启发性。
-
您好@EJP,我阅读了这篇文章link
smart-proxy,然后我修改了SecurityInvocationHandler 类,带有这个签名:public class SecurityInvocationHandler<T> implements InvocationHandler, Serializable {及其构造函数。现在,客户端查找代理对象,但 InvocationHandler 在客户端运行.. -
当然可以。它不是一个导出的远程对象,所以它被序列化到客户端,并在那里执行。假设您退后一步,准确告诉我们您要完成的工作是什么?
-
所以,我会实现一个安全层,进行登录,限制特定客户端的方法调用等。昨天阅读了这篇文档[A Framework for Smart Proxies and Interceptors in RMI](citeseerx.ist.psu.edu/viewdoc/… ) 它解释了我会做什么,但有两个问题,我在下面引用:
-
"方法编组:另一个必须解决的问题是编组方法调用请求。直接使用RMI时,远程对象的存根处理这个任务。服务对象丢失时stub 被动态代理取代。因此,有必要实现一种将方法调用转发到服务器的机制。ServerProxy 是用于此目的的 Remote 对象。它足够通用,因此任何方法调用都可以使用可以通过它发送任意数量的参数。”
标签: java rmi classcastexception dynamic-proxy