[Oracle ADF] Row Level Security using VPD and ADF - Шаг 1 - Настраиваем контексты, процедуры, подготавливаем appmodule
По материалам: Row level Security using ADF and Sys_context package
http://dba-adf.blogspot.ru/2012/07/row-level-security-using-adf-and.html
ШАГ 1:
Выполняется под учеткой пользователя в базе данных! В моем случае в SQL Developer.
Создаю контекстную переменную в базе, которая будет хранить залогиненого пользователя и обновляться при логине:
CREATE OR REPLACE CONTEXT SEC_CTX
USING SEC_CTX_PKG
ACCESSED GLOBALLY;
Далее базе создаю пакет:
create or replace PACKAGE SEC_CTX_PKG IS
PROCEDURE SET_SESSION_ID (IN_SESSION_ID VARCHAR2);
PROCEDURE SET_CONTEXT (IN_NAME VARCHAR2, IN_VALUE VARCHAR2);
FUNCTION RETURN_CONTEXT RETURN VARCHAR2;
END SEC_CTX_PKG;
create or replace PACKAGE BODY SEC_CTX_PKG
IS
GC$SESSION_ID VARCHAR2 (100);
PROCEDURE SET_SESSION_ID (IN_SESSION_ID VARCHAR2)
IS
BEGIN
GC$SESSION_ID := IN_SESSION_ID;
DBMS_SESSION.SET_IDENTIFIER (IN_SESSION_ID);
END;
-------------------------------------------------------------------------------------------------
PROCEDURE SET_CONTEXT (IN_NAME VARCHAR2, IN_VALUE VARCHAR2)
IS
BEGIN
DBMS_SESSION.SET_CONTEXT ('SEC_CTX', IN_NAME, IN_VALUE, USER, GC$SESSION_ID);
END;
-------------------------------------------------------------------------------------------------
FUNCTION RETURN_CONTEXT
RETURN VARCHAR2 AS
RES1 varchar2(80);
BEGIN
SELECT SYS_CONTEXT ('SEC_CTX', 'user_id') INTO RES1 FROM DUAL;
RETURN RES1;
END RETURN_CONTEXT;
------------------------------------------------------------------------------------------------
END SEC_CTX_PKG;
В AppModuleImpl добавляю следующий код:
Код написан для тестирования! А не для того, чтобы поразить всех красотой и изяществом! И да, у меня он всегда такой получается!
@Override
protected void prepareSession(Session session) {
super.prepareSession(session);
setVPDcontext();
checkContextFromDB();
}
private void setVPDcontext() {
SessionImpl sessionImpl = (SessionImpl)getDBTransaction().getSession();
String loggedInUser = sessionImpl.getUserPrincipalName();
CallableStatement stmt = null;
try {
String sql = "BEGIN SEC_CTX_PKG.SET_SESSION_ID ('" + loggedInUser + "'); SEC_CTX_PKG.SET_CONTEXT ('user_id', '" + loggedInUser + "'); END; ";
stmt = this.getDBTransaction().createCallableStatement(sql, 0);
stmt.execute();
} catch (Exception ex) {
LOGGER.severe("EXCEPTION " + ex.toString());
ex.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (Exception ex) {
LOGGER.severe("EXCEPTION " + ex.toString());
ex.printStackTrace();
}
}
}
}
public void checkContextFromDB(){
System.out.println("");
System.out.println("");
System.out.println("out " + getContextFromDB());
System.out.println("");
System.out.println("");
}
private String getContextFromDB(){
CallableStatement stmt = null;
String function_execute = "begin ?:= SEC_CTX_PKG.RETURN_CONTEXT; end;";
try {
stmt = this.getDBTransaction().createCallableStatement(function_execute, 1);
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.execute();
String out = stmt.getString(1);
return out;
} catch (Exception exp) {
System.out.println("EXCEPTION EX " + exp.toString());
// exp.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
return "";
}
this.getDBTransaction() следует заменить DBUtils.getDBTransaction(), если делать вызов в каком-нибудь бине. Но когда я делал в бине, контекст время от времени терялся. Поэтому оставил в AppModule.
Теперь при логине получаю в консоли логин зарегистрированного пользователя.
И вывожу тоже самое из SEC_CTX.
Далее создаю ViewObject, что-то вроде:
SELECT *
FROM user_info
WHERE user_id = SYS_CONTEXT ('SEC_CTX', 'user_id');
И бросаю его на форму, конкретно в моем случае, это таблица.
Offtopic. Вроде можно и так сделать, а не как у автора статьи. Впрочем мне сейчас не до проверяния всего этого.
Работает, не трогай. Похвалить не похвалят, а сломаешь накажут.
PROCEDURE SET_SESSION_ID (IN_SESSION_ID VARCHAR2)
IS
BEGIN
DBMS_SESSION.SET_IDENTIFIER (IN_SESSION_ID);
END;
-------------------------------------------------------------------------------------------------
PROCEDURE SET_CONTEXT (IN_NAME VARCHAR2, IN_VALUE VARCHAR2)
IS
BEGIN
DBMS_SESSION.SET_CONTEXT ('SEC_CTX', IN_NAME, IN_VALUE, USER);
END;