In one of my developments we came across a requirement to provide display access to a transactional app. This was for a wider audience than the app was previously designed for. Now to cater to this we had two options –
- Build a brand-new app which is not transactional. Have a new tile and provide access to the new user group to this tile.
- Incorporate authority checks in the existing app.
Another driving factor was that we found this statement in “SAP UI5 SDK in the Security section –
“Moreover, common security mechanisms, which are usually taken for granted, like user authentication, session handling, authorization handling, or encryption are not part of SAPUI5 and need to be handled by the server-side framework and/or custom code of the application
In this blog I will discuss the second approach and how I implemented it. I have used the same app as my previous blog “10 Interesting hacks for UI5 apps using Fiori Elements”. So if someone would like to experiment you can get the entire source code from there and just plug in the parts that I will discuss here.
The video of the app will show it in action. First, I login with as a user who is authorized to edit. Later as a display only user.
Steps are as follows –
1. Create a new Authorization Object (SU21)
2. Create two roles in PFCG and assign the new authorization object to the roles. One is a “Display” role and other is a “Admin” role. Assign the roles to distinct users to test (SU01). You will most probably need SAP security team help for this step. Here is the screenshot of the “Display” user’s role.
3. To do the authority checks I created a new entity called ETY_AUTHORITY in the odata service. The reason for this is that we need to do the authority checks in ABAP. The actual data for the app is still coming from CDS views (which are referenced in oData service to leverage SADL capabilities)
METHOD ets_authority_get_entityset.
DATA ls_entity LIKE LINE OF et_entityset.
AUTHORITY-CHECK OBJECT 'ZORDER'
ID 'ACTVT' FIELD '02'.
"if authority check fails set it to uneditable
IF sy-subrc <> 0.
ls_entity-editable = ''.
ELSE.
ls_entity-editable = 'X'.
ENDIF.
APPEND ls_entity TO et_entityset.
ENDMETHOD.
4. Now the frontend. In our UI5 app create a simple model file with methods to handle authority checks from backend. I have done this to ensure that the backend is called only once to check for authorization during the app lifecycle(The JavaScript file name is Model.js).sap.ui.define([], function() {
"use strict";
var auth;
return {
setAuthority:function(){
auth = 'X';
},
getAuthority: function(){
return auth;
}
};
});
5. In the onInit() method of ListReportExt I make the oData backend call for authority and the result I save it in the Model(see step 4). If the authority check fails, I set the Create and Delete button to invisible.jQuery.sap.require("zcustomorder.model.Model");
sap.ui.controller("zcustomorder.ext.controller.ListReportExt", {
//Local Model declaration
Model: sap.ui.require("zcustomorder/model/Model"),
onInit: function(){
//Somehow the chart entity is not called automatically so we need to call it explicitly to load
this._loadChart();
that = this;
//Authority Check Logic
var url = "/ETS_AUTHORITY";
var functionSucess = function (oData, controller) {
sap.ui.core.BusyIndicator.hide();
var result = oData.results[0];
if(result.Editable == ''){
that.Model.setAuthority();
var creButAll = that.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--addEntry-t0"
);
var delButAll = that.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--deleteEntry-t0"
);
if(creButAll){
creButAll.setVisible(false);
}
if(delButAll){
delButAll.setVisible(false);
}
}
};
var params = {
async: false,
success: function (oData, controller) {
functionSucess(oData, controller);
},
error: function (oError) {
sap.ui.core.BusyIndicator.hide();
}
};
var oModel = this.getOwnerComponent().getModel();
oModel.read(url, params);
//End of Authority Check Logic
//Auto value help logic for Smart Filter
var smFilt = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--listReportFilter"
);
var conConfig = smFilt.getControlConfiguration();
conConfig.forEach(function(item, idx, arr){
smFilt.removeControlConfiguration(item);
item.setPreventInitialDataFetchInValueHelpDialog(false);
smFilt.addControlConfiguration(item);
}, this);
}
});
6. It was a bit challenging for ObjectPage changes as we have to deal with line item level navigation and initialization is done only once. So, if we simply put the checks in onAfterRendering() method then the checks will work only for first entry and not the subsequent ones. To overcome this problem I put the logic to hide the “Edit” and “Delete” buttons in attachRequestCompleted() method which is called every time since the view data needs to be fetched from backend. Also note that I now use the Model.getAuthority() instead of making a backend call.jQuery.sap.require("zcustomorder.model.Model");
sap.ui.controller("zcustomorder.ext.controller.ObjectPageExt", {
//Local Model declaration
Model: sap.ui.require("zcustomorder/model/Model"),
onInit: function () {
that = this;
//Automatic value help for Object Page smart field
var fld = this.oView.byId("zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field");
if (fld) {
var oConfig = fld.getConfiguration();
if (!oConfig) {
oConfig = new sap.ui.comp.smartfield.Configuration();
}
oConfig.setPreventInitialDataFetchInValueHelpDialog(false);
oConfig.setDisplayBehaviour(sap.ui.comp.smartfield.DisplayBehaviour.descriptionAndId);
fld.setConfiguration(oConfig);
}
//Convert Smart field into URL
var notifFld = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field"
);
if (notifFld) {
notifFld.attachPress(this.onNotifPress);
}
// This will ensure that view context is loaded and Stndard buttons can be accessed
this.getOwnerComponent().getModel().attachRequestCompleted(function () {
var sPath = that.getView().getBindingContext() ? that.getView().getBindingContext().getPath() : '';
if (sPath != '') {
that.hideButtons();
}
});
},
hideButtons : function(){
var oEdit = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--edit");
var oDelete = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--delete");
if(that.Model.getAuthority()){
oEdit.setVisible(false);
oDelete.setVisible(false);
}
}
});
That’s all folks. Hope you enjoyed the Blog.
Source: https://blogs.sap.com/2019/07/07/authorization-checks-in-apps-using-sap-fiori-elements/
Nenhum comentário:
Postar um comentário