=====Oracle Apex 5 - Authorization Scheme in PL/SQL umsetzen===== **Die Aufgabe:** Je nachdem in welcher Gruppe ein User ist sollen bestimmte Menü Elemente angezeigt werden und der Anwender soll das entsprechende Admin Formular aufrufen können. Da es sich um über 50 Stammdaten Tabellen mit wachsender Tendenz handelt, die ganz unterschiedlichen Benutzern zur Verfügung stehen sollen, wird es rein mit Gruppen in Apex ohne weitere Logik schwierig. Zusätzlich können nicht alle 50 Masken ohne Test in Produktion gestellt werden, d.h. in der Produktion sollen nur die Masken angezeigt werden, die "enabled" sind. Die Standard Administratoren sollen das Rechte behalten, ohne Kontrolle im Detail, die Masken aufrufen zu können. Die Pflege, welche APEX Rolle die Tabelle bearbeiten kann, soll in der Apex Oberfläche bearbeitet werden können. **Lösung:** * ADMIN Gruppe für die Haupt Administratoren - volle Rechte * BUSINESS Gruppe für die Sachbearbeiter, die Sachbearbeiter können sich an der App anmelden * FACHBEREICH Gruppe für den Sachbearbeiter, dieser Gruppe regelt die Rechte auf die Maske der Stammdaten Tabelle In einer Master Tabelle mit allen Informationen über die Stammdaten Masken wird hinterlegt welche FACHBEREICH Gruppe Rechte auf die Maske hat, dies erfolgt über Mitglieder der ADMIN Gruppe. In dieser Tabelle ist auch die ID der Maske hinterlegt mit der die Pflege erfolgen soll, darüber kann wieder zurück auf das Navigationselement für die Maske gefolgert werden. Damit also ein Sachbearbeiter die Maske sieht, benötigt er die BUSINESS Gruppe und die richtige FACHBEREICH Gruppe, das muss über die Workspace User Verwaltung zuvor zugeordnet werden. Auf allen Parameter Seiten und allen Navigations List Elementen ist ein Authorization Scheme "PARAM" hinterlegt. Über "Shared Components \ Authorization Schemes \ " wird dieses Scheme als PL/SQL Scheme angelegt. Nun können wir das ganze individuell mit unseren eigenen Regeln umsetzen. ---- ==== Code ==== Die wichtigsten Komponenten des Codes sind: ==Aus welchen Kontext wird aufgerufen== apex_debug.message('app_component_id = ' || :APP_COMPONENT_ID); apex_debug.message('app_component_name = ' || :APP_COMPONENT_NAME); apex_debug.message('app_component_type = ' || :APP_COMPONENT_TYPE); Funktioniert aber nur wenn der „Evaluation Point“ des Schemas auf „Once per component“ oder "Always (No Caching)" steht!! == Welchen Gruppen ist der User zugeordnet== -- get the user groups v_group_list := apex_util.GET_GROUPS_USER_BELONGS_TO(p_username => :APP_USER); == Ist die Komponente vom Typ "APEX_APPLICATION_LIST_ENTRIES", auf was zeigt das Element?== select replace(regexp_substr(entry_target, '[f?p=&APP_ID.:][[:digit:]]+[:]'),':','') into v_page_link from APEX_APPLICATION_LIST_ENTRIES where LIST_ENTRY_ID = :APP_COMPONENT_ID; apex_debug.message('v_page_link for APP_COMPONENT_ID = ' || :APP_COMPONENT_ID || ' = ' || v_page_link); === Der komplette Code === declare v_return boolean := false; v_group_list varchar2(32000); v_page_title varchar2(256); v_business_user varchar2(256); v_table_text varchar2(32000); v_page_link varchar2(256); v_enabled varchar2(256); begin --debug apex_debug.message('app_component_id = ' || :APP_COMPONENT_ID); apex_debug.message('app_component_name = ' || :APP_COMPONENT_NAME); apex_debug.message('app_component_type = ' || :APP_COMPONENT_TYPE); -- get the user groups v_group_list := apex_util.GET_GROUPS_USER_BELONGS_TO(p_username => :APP_USER); -- check for parameter user if :APP_COMPONENT_TYPE not like 'APEX_APPLICATION_LIST_ENTRIES' then -- check over ADMIN_TABLES if the user can access this page begin select BUSINESS_USER_GROUP , ENABLED into v_business_user ,v_enabled from ADMIN_TABLES where PAGEID = :APP_PAGE_ID; exception when no_data_found then select PAGE_TITLE into v_page_title from APEX_APPLICATION_PAGES where PAGE_ID = :APP_PAGE_ID and APPLICATION_ID = :APP_ID; v_table_text := 'APP_COMPONENT_NAME := ' || :APP_COMPONENT_NAME || 'APP_COMPONENT_TYPE := ' || :APP_COMPONENT_TYPE || 'APP_COMPONENT_ID := ' || :APP_COMPONENT_ID; apex_debug.message('Admin Table not found ::' || v_table_text); -- insert to the admin table the missing record insert into ADMIN_TABLES(TABLE_NAME ,SHORT_DESC ,LONG_DESC ,PAGEID) values (substr(v_page_title, 1, 32) ,'Fix :: missing Admin Table Text' ,v_table_text , :APP_PAGE_ID); commit; end; else -- get the Menü item to this Param table -- over the APP_COMPONENT_ID := --select entry_target, from APEX_APPLICATION_LIST_ENTRIES where LIST_ENTRY_ID=:APP_COMPONENT_ID select replace(regexp_substr(entry_target, '[f?p=&APP_ID.:][[:digit:]]+[:]'),':','') into v_page_link from APEX_APPLICATION_LIST_ENTRIES where LIST_ENTRY_ID = :APP_COMPONENT_ID; apex_debug.message('v_page_link for APP_COMPONENT_ID = ' || :APP_COMPONENT_ID || ' = ' || v_page_link); begin if v_page_link != '-' then select BUSINESS_USER_GROUP , ENABLED into v_business_user , v_enabled from ADMIN_TABLES where PAGEID = to_number(v_page_link); else v_business_user := 'n/a'; end if; exception when others then v_business_user := 'n/a'; apex_debug.message('Error get Page Link Nav Info ::' || sqlerrm); end; end if; ---------- if instr(v_group_list, 'BUSINESS_USER') > 0 then if instr(upper(v_group_list), upper(v_business_user)) > 0 then v_return := true; end if; end if; -- check for Admin User if instr(v_group_list, 'ADMIN_USER') > 0 then v_return := true; end if; -- show only enabled admin tables if :APP_COMPONENT_TYPE = 'APEX_APPLICATION_LIST_ENTRIES' and v_enabled = 'N' then v_return := false; end if; return v_return; end; Darauf achten das der "Evaluation Point" des Schemas auf "Once per component" stehen muss! ---- ==== Quellen ==== Blogs: * http://www.explorer.uk.com/component-level-authorization-apex-5-0/ * https://www.apex-at-work.com/2012/07/getting-apex-views.html Doku: * https://docs.oracle.com/cd/E71588_01/AEAPI/APEX_UTIL.htm#AEAPI101