我正在RMI中开发一个安全的银行服务,其中包含服务器和客户端的GUI。
服务器必须能够记录每个操作(新用户,已删除的用户,提款,寄存...) 客户将执行这些操作。 由于一切都是安全的,客户端必须首先在GUI中创建一个具有名称和密码的帐户。之后,GUI将Bank UserList(arrayList)中的User添加为新Customer,User可以执行多个操作。 起初看起来很简单,但我认为我的观念不正确。
通过RMI发送整个银行是否正确?因为起初我以为Bank会成为服务器,但我找不到另一种方法。 目前,客户端GUI要求登录和密码,并通过RMI接收银行。用户的名称和密码的哈希值。
private String name;
private byte[] passwordDigest;
事实上,GUI正在进行所有安全检查,我不知道它是否相关。当您键入login // password时,它将搜索Bank中的登录名并比较密码的哈希值。 事实上,我的印象是客户知道太多信息,因为当你拥有银行时,你拥有一切......
它看起来是正确的还是我需要更改我的实现?
答案 0 :(得分:2)
您需要两个远程对象类。
第一个是通过Naming.lookup()
获得的;它是一个单身人士;它包含login()
方法。
此方法返回第二个远程对象,该对象不是单例,未在注册表中注册,而是为每个返回值重新创建。此对象包含所有银行业务方法以及logout()
方法,该方法不会将其取消;它可能还实现了Unreferenced
接口,因此它可以检测死客户端,并取消导出自身。因为它每个客户端存在一次,所以它可以保存客户端状态,并且因为它只能通过成功的登录步骤获得,所以它解决了您的安全问题。
public interface Login extends Remote
{
Session login(String username, char[] password /* or whatever */)
throws LoginException, RemoteException;
}
public interface Session extends Remote
{
void logout() throws RemoteException;
void deposit(...) throws RemoteException;
void withdraw(...) throws RemoteException;
}
public class LoginImpl extends UnicastRemoteObject implements Login
{
public Session login(String username, char[] password)
throws LoginException, RemoteException
{
// username/password check; if it fails throw a LoginException
return new SessionImpl(username); // or whatever
}
}
public class SessionImpl extends UnicastRemoteObject implements Session, Unreferenced
{
public void logout() throws RemoteException
{
unexportObject(this, true);
}
public void unreferenced()
{
unexportObject(this, true); // needs to be in a try/catch block of course
}
// etc
}
我在2001年的书中将其描述为远程会话模式。
当然 还需要传输层安全性:请参阅javax.rmi.ssl.
答案 1 :(得分:1)
您误解了远程接口的工作原理。客户端不拥有银行,它只能引用银行的远程实例。客户端在Bank界面上进行的所有方法调用实际上都是针对银行的远程实例(在服务器中运行)进行远程调用。
据推测,安全检查是在每个方法调用上的内部 中完成的。
。