代理认证使中间层能够用"普通(generic)"或"应用程序(application)"账户对数据库的访问进行认证,然后即代表真实的用户建立轻便会话。一个代理会话可以通过提交用户的辨认名(distinguished name (dn)),即一个x.509证书,或全局唯一用户名来建立。
例如,为了允许用户kyle通过具有角色admin的中间层(它作为用户webapp保持一个连接池)连接到数据库,数据库管理员首先授予如下的权限:alter user kyle grant connect through webapp with role admin;
接着,该应用程序代码(在这里是一个Servlet)翻译从web接收到的用户名并建立如下所示的代理会话:
string username = request.getremoteuser();
initialcontext initial =
new initialcontext();
oracleociconnectionpool ds =
(oracleociconnectionpool)
initial.lookup("jdbc/oracleocids");
oracle.jdbc.oracleconnection conn = null;
properties p = new properties();
p.setproperty(proxy_user_name, username);
conn = ds.getproxyconnection(
proxytype_user_name, p);
代理认证允许使用包括脚色在内的所有数据库安全性功能,但是它要求你设置真实的数据库用户(数据库或企业)。
使用client_identifier
但是,假定你有成百上千的用户,而你不想为每个用户都设立一个oracle数据库或企业用户。那么你也可以通过使用应用程序上下文将用户身份从中间层传递到该数据库。
应用程序上下文是一组可用于数据库会话的名字/值对。oracle9i有预定义的应用程序上下文名字空间userenv,它含有用户会话信息,包括预定义的属性client_identifier。这一属性通常用作从全局应用程序上下文选取值的会话标识符,但是我们将稍加变更,将它用于保持web用户标识符。
从servlet或enterprise Javabeans (ejb)会话bean,应用程序代码将从web请求检索用户名,然后调用内部pl/sql过程设置client_identifier:
string username = request.getremoteuser();
...(set up the jdbc connection)...
preparedstatement ps = conn.preparecall(
"begin dbms_session.set_identifier(?);
end;");
ps.setstring(1, username);
ps.execute();
select sys_context('userenv', 'client_identifier') from dual;
使用这种方法没有使用代理认证那样安全。因为任何人都能设置这个上下文值,你必须借助额外的安全性措施,如细粒度的访问控制和安全的应用程序角色等。你的应用程序还应在将数据库连接返回给连接池之前清除client_identifier属性。