Requirement is to have Managed App Router based Fiori app in SAP BTP- CF which is calling OData/web service(We have taken example of Northwind for this project) and add additinal authorization layer with the help of XSUAA to achieve in app authorization.
Here Node JS API and HTML5 modules are added in single MTA sharing instance of XSUAA
and communicating with the help of OAuth2UserTokenExchange type instance level destination.
Note: Destinations are created with help of MTA.yaml dependencies.
You can find complete project at GitHub
Step1:Create Basic MTA
Step2:Add Managed App Router
Right click on MTA.yaml and select create MTA Module from Template
Step3:Add Fiori/SAPUI5 Module in MTA
Step4:Add Node JS Module to add additinal layer for calling web service/OData.
Add Node JS module in MTA04 project to call Northwind service and add XSUAA Auth. Refer GitHub Project.
Below code you can refer for Node JS API which is calling Northwind service. Folder structure can be referred from Git project shared above.
const express = require("express");
const fetch = require("axios");
const app = express();
const port = process.env.port || 8080;
const { JWTStrategy } = require("@sap/xssec");
const xsenv = require("@sap/xsenv");
const passport = require("passport");
passport.use(new JWTStrategy(xsenv.getServices({ uaa: { tag: "xsuaa" } }).uaa));
app.use(passport.initialize());
app.use(passport.authenticate("JWT", { session: false }));
app.get("/", (req, res, next) => {
res.send("Node Js Based Service With App Router for SAP BTP CF by Satyajit");
});
app.get("/PRD/Products", checkScope, async (req, res, next) => {
var result;
result = await fetch.get("https://services.odata.org/v2/northwind/northwind.svc/Products?$format=json")
res.send(result.data);
});
function checkScope(req, res, next) {
if (req.authInfo.checkLocalScope("read")) {
next();
} else {
res.status(403).end("Forbidden");
}
}
app.listen(port, console.log(`Listening on port ${port}`));
Step5:Make AJAX call to Node JS service.
sap.ui.define([
"sap/ui/core/mvc/Controller"
],
/**
* @param {typeof sap.ui.core.mvc.Controller} Controller
*/
function (Controller) {
"use strict";
return Controller.extend("ns.mta04.mta04.controller.View1", {
onInit: function () {
let path = this.getOwnerComponent().getManifestObject()._oBaseUri._parts.path;
var sUrl = path + "PRD/Products";
//var oView = this.getView();
var oTextModel = this.getOwnerComponent().getModel("textModel");
//this.getView().setModel(oTextModel,"textModel");
var oTable = this.getView().byId("idTabel01");
jQuery.ajax({
url: sUrl,
method: "GET",
success: function (oResponse) {
debugger;
oTextModel.setData(oResponse.d.results);
oTable.setModel(oTextModel);
oTable.bindRows("textModel>/");
},
error: function () {
debugger;
}
});
}
});
});
View1.view.xml code
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:m="sap.m" xmlns="sap.ui.table" controllerName="ns.mta04.mta04.controller.View1" displayBlock="true">
<m:Page id="page" title="{i18n>title}">
<m:content>
<Table enableCellFilter="true" selectionMode="None" visibleRowCount="15" id="idTabel01" rows="{textModel>/}">
<columns>
<Column id="c1" width="25%">
<m:Label text="Product ID" id="l1"/>
<template>
<m:Text text="{textModel>ProductID}" id="t1" />
</template>
</Column>
<Column width="50%" id="c2">
<m:Label text="Product Name" id="l2" />
<template>
<m:Text text="{textModel>ProductName}" id="t2" />
</template>
</Column>
<Column width="25%" id="c3">
<m:Label text="Unit Price" id="l3" />
<template>
<m:Text text="{textModel>UnitPrice}" id="t3" />
</template>
</Column>
</columns>
</Table>
</m:content>
</m:Page>
</mvc:View>
Adjust MTA.yaml as below.
_schema-version: "3.2"
ID: MTA04
version: 0.0.1
modules:
- name: API_NodeJS
type: nodejs
path: ./API_WITH_XSUAA
requires:
- name: uaa_MTA04
provides:
- name: srv-api-nodejs
properties:
srv-url: ${default-url}
parameters:
buildpack: nodejs_buildpack
build-parameters:
builder: npm-ci
- name: MTA04-destination-content
type: com.sap.application.content
requires:
- name: MTA04-destination-service
parameters:
content-target: true
- name: MTA04_html_repo_host
parameters:
service-key:
name: MTA04_html_repo_host-key
- name: srv-api-nodejs
- name: uaa_MTA04
parameters:
service-key:
name: uaa_MTA04-key
parameters:
content:
instance:
destinations:
- Authentication: OAuth2UserTokenExchange
Name: api-nodejs-srv
TokenServiceInstanceName: MTA04-xsuaa-service
TokenServiceKeyName: uaa_MTA04-key
URL: ~{srv-api-nodejs/srv-url}
- Name: MTA04_MTA04_html_repo_host
ServiceInstanceName: MTA04-html5-app-host-service
ServiceKeyName: MTA04_html_repo_host-key
sap.cloud.service: MTA04
- Authentication: OAuth2UserTokenExchange
Name: MTA04_uaa_MTA04
ServiceInstanceName: MTA04-xsuaa-service
ServiceKeyName: uaa_MTA04-key
sap.cloud.service: MTA04
existing_destinations_policy: ignore
build-parameters:
no-source: true
- name: MTA04-app-content
type: com.sap.application.content
path: .
requires:
- name: MTA04_html_repo_host
parameters:
content-target: true
build-parameters:
build-result: resources
requires:
- artifacts:
- nsmta04mta04.zip
name: nsmta04mta04
target-path: resources/
- name: nsmta04mta04
type: html5
path: mta04
build-parameters:
build-result: dist
builder: custom
commands:
- npm install
- npm run build:cf
supported-platforms: []
resources:
- name: MTA04-destination-service
type: org.cloudfoundry.managed-service
parameters:
config:
HTML5Runtime_enabled: true
init_data:
instance:
destinations:
- Authentication: NoAuthentication
Name: ui5
ProxyType: Internet
Type: HTTP
URL: https://ui5.sap.com
existing_destinations_policy: update
version: 1.0.0
service: destination
service-name: MTA04-destination-service
service-plan: lite
- name: MTA04_html_repo_host
type: org.cloudfoundry.managed-service
parameters:
service: html5-apps-repo
service-name: MTA04-html5-app-host-service
service-plan: app-host
- name: uaa_MTA04
type: org.cloudfoundry.managed-service
parameters:
path: ./xs-security.json
service: xsuaa
service-name: MTA04-xsuaa-service
service-plan: application
parameters:
deploy_mode: html5-repo
Step6:Deploy app to CF and add add to FLP service.
Right click on MTA.YAML and click on Build MTA Project.
Add Fiori Application to Fiori Launchpad service
** If Launchpad service is not available create new subscription.
Add App to group and Role. It will be available in FLP service.
Also app can be tested form HTML5 repo
Conclusion-
With this kind of scenario we can implement additinal authorization at BTP level.
We can use this project to call any S4 API also with the help of destination at subaccount level.
Please share your feedback.