保护使用 SAP Cloud SDK 构建的 JS 应用程序
Securing a JS application built with SAP Cloud SDK
我正在按照 developers.sap.com 上的教程学习 Javascript:
Get Started with SAP Cloud SDK for JavaScript.
我创建了我的应用程序:
sap-cloud-sdk init my-sdk-project
现在我想为其增加安全性,具体来说,我想使用批准程序访问该应用程序,并且我想直接阻止对服务的任何未经身份验证的请求。
或者,我想为我的应用程序的不同端点包含范围。
添加approuter我没有任何问题,但是在保护节点应用程序时,我似乎找不到正确的方法。
我只能找到使用基本 Express 节点应用程序保护应用程序的示例,例如:
Hello World Sample using NodeJS
但是它们与 sap-cloud-sdk
工具提供的结构不同,后者使用 nestjs
。
如果您使用的是 Nestjs,Help Portal 也不会指向任何示例。
是否有任何资源、教程或示例可以帮助我在脚手架应用程序中实现安全性?
氪,
配对
目前还没有关于如何使用 Cloud SDK for JS 设置 Cloud Foundry 安全性的资源,但我过去对它进行了一些修改,结果如下。
免责声明: 这绝不是生产就绪代码!请仅将此作为灵感,并通过测试验证您这边的所有行为,并添加强大的错误处理!
引入一个scopes.decorator.ts
文件,内容如下:
import { SetMetadata } from '@nestjs/common';
export const ScopesMetadataKey = 'scopes';
export const Scopes = (...scopes: string[]) => SetMetadata(ScopesMetadataKey, scopes);
这将创建一个注释,您可以在后续步骤中将其添加到控制器方法中。给定的参数将是调用端点之前需要的范围。
像下面这样创建一个守卫scopes.guard.ts
:
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { retrieveJwt, verifyJwt } from '@sap/cloud-sdk-core';
import { getServices } from '@sap/xsenv';
import { ScopesMetadataKey } from './scopes.decorator';
@Injectable()
export class ScopesGuard implements CanActivate {
private xsappname;
constructor(private readonly reflector: Reflector) {
this.xsappname = getServices({ uaa: { label: 'xsuaa' } }).uaa.xsappname;
}
async canActivate(context: ExecutionContext): Promise<boolean> {
const scopes = this.reflector.get<string[]>(ScopesMetadataKey, context.getHandler());
if (!scopes) {
return true;
}
const request = context.switchToHttp().getRequest();
const encodedJwt = retrieveJwt(request);
if (!encodedJwt) {
return false;
}
const jwt = await verifyJwt(encodedJwt);
return this.matchScopes(scopes, jwt.scope);
}
private matchScopes(expectedScopes: string[], givenScopes: string[]): boolean {
const givenSet = new Set(givenScopes);
return expectedScopes.every(scope => givenSet.has(this.xsappname + '.' + scope));
}
}
应在所有端点之前调用此 Guard,并验证传入的 JWT 中是否存在所有需要的范围。
将守卫添加到您的 Nest 应用程序设置中:
import { Reflector } from '@nestjs/core';
import { ScopesGuard } from './auth/scopes.guard';
// ...
const app = ...
const reflector = app.get(Reflector)
app.useGlobalGuards(new ScopesGuard(reflector));
// ...
这确保所有传入的请求实际上都是 "guarded" 上面的守卫。
在值得保护的端点上使用第一步中创建的注释:
import { Controller, Get } from '@nestjs/common';
import { Scopes } from '../auth/scopes.decorator';
@Controller('/api/rest/foo')
export class FooController {
constructor(private readonly fooService: FooService) {}
@Get()
@Scopes('FooViewer')
getFoos(): Promise<Foo[]> {
return this.fooService.getFoos();
}
}
现在仅当提供具有所需范围的 JWT 时才可调用此端点。
您可以在 sap-cloud-sdk/nest.js 项目中使用标准的 nodejs 身份验证实现,而无需创建任何中间件。
由于作为 @sap/xssec 一部分的 JWTStrategy 具有中间件实现,因此事情非常简单。
- 对于身份验证更改
main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { getServices } from '@sap/xsenv';
const xsuaa = getServices({ xsuaa: { tag: 'xsuaa' } }).xsuaa;
import * as passport from 'passport';
import { JWTStrategy } from '@sap/xssec';
passport.use(new JWTStrategy(xsuaa));
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));
await app.listen(process.env.PORT || 3000);
}
bootstrap();
这将初始化中间件。
2. 范围检查和授权
import { Controller, Get, Req, HttpException, HttpStatus } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) { }
@Get()
getHello(@Req() req: any): any {
console.log(req.authInfo);
const isAuthorized = req.authInfo.checkLocalScope('YourScope');
if (isAuthorized) {
return req.user;
} else {
return new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
// return this.appService.getHello();
}
}
详情请参考this
我正在按照 developers.sap.com 上的教程学习 Javascript: Get Started with SAP Cloud SDK for JavaScript.
我创建了我的应用程序:
sap-cloud-sdk init my-sdk-project
现在我想为其增加安全性,具体来说,我想使用批准程序访问该应用程序,并且我想直接阻止对服务的任何未经身份验证的请求。 或者,我想为我的应用程序的不同端点包含范围。
添加approuter我没有任何问题,但是在保护节点应用程序时,我似乎找不到正确的方法。
我只能找到使用基本 Express 节点应用程序保护应用程序的示例,例如:
Hello World Sample using NodeJS
但是它们与 sap-cloud-sdk
工具提供的结构不同,后者使用 nestjs
。
如果您使用的是 Nestjs,Help Portal 也不会指向任何示例。
是否有任何资源、教程或示例可以帮助我在脚手架应用程序中实现安全性?
氪, 配对
目前还没有关于如何使用 Cloud SDK for JS 设置 Cloud Foundry 安全性的资源,但我过去对它进行了一些修改,结果如下。
免责声明: 这绝不是生产就绪代码!请仅将此作为灵感,并通过测试验证您这边的所有行为,并添加强大的错误处理!
引入一个
scopes.decorator.ts
文件,内容如下:import { SetMetadata } from '@nestjs/common'; export const ScopesMetadataKey = 'scopes'; export const Scopes = (...scopes: string[]) => SetMetadata(ScopesMetadataKey, scopes);
这将创建一个注释,您可以在后续步骤中将其添加到控制器方法中。给定的参数将是调用端点之前需要的范围。
像下面这样创建一个守卫
scopes.guard.ts
:import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { retrieveJwt, verifyJwt } from '@sap/cloud-sdk-core'; import { getServices } from '@sap/xsenv'; import { ScopesMetadataKey } from './scopes.decorator'; @Injectable() export class ScopesGuard implements CanActivate { private xsappname; constructor(private readonly reflector: Reflector) { this.xsappname = getServices({ uaa: { label: 'xsuaa' } }).uaa.xsappname; } async canActivate(context: ExecutionContext): Promise<boolean> { const scopes = this.reflector.get<string[]>(ScopesMetadataKey, context.getHandler()); if (!scopes) { return true; } const request = context.switchToHttp().getRequest(); const encodedJwt = retrieveJwt(request); if (!encodedJwt) { return false; } const jwt = await verifyJwt(encodedJwt); return this.matchScopes(scopes, jwt.scope); } private matchScopes(expectedScopes: string[], givenScopes: string[]): boolean { const givenSet = new Set(givenScopes); return expectedScopes.every(scope => givenSet.has(this.xsappname + '.' + scope)); } }
应在所有端点之前调用此 Guard,并验证传入的 JWT 中是否存在所有需要的范围。
将守卫添加到您的 Nest 应用程序设置中:
import { Reflector } from '@nestjs/core'; import { ScopesGuard } from './auth/scopes.guard'; // ... const app = ... const reflector = app.get(Reflector) app.useGlobalGuards(new ScopesGuard(reflector)); // ...
这确保所有传入的请求实际上都是 "guarded" 上面的守卫。
在值得保护的端点上使用第一步中创建的注释:
import { Controller, Get } from '@nestjs/common'; import { Scopes } from '../auth/scopes.decorator'; @Controller('/api/rest/foo') export class FooController { constructor(private readonly fooService: FooService) {} @Get() @Scopes('FooViewer') getFoos(): Promise<Foo[]> { return this.fooService.getFoos(); } }
现在仅当提供具有所需范围的 JWT 时才可调用此端点。
您可以在 sap-cloud-sdk/nest.js 项目中使用标准的 nodejs 身份验证实现,而无需创建任何中间件。 由于作为 @sap/xssec 一部分的 JWTStrategy 具有中间件实现,因此事情非常简单。
- 对于身份验证更改
main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { getServices } from '@sap/xsenv';
const xsuaa = getServices({ xsuaa: { tag: 'xsuaa' } }).xsuaa;
import * as passport from 'passport';
import { JWTStrategy } from '@sap/xssec';
passport.use(new JWTStrategy(xsuaa));
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));
await app.listen(process.env.PORT || 3000);
}
bootstrap();
这将初始化中间件。 2. 范围检查和授权
import { Controller, Get, Req, HttpException, HttpStatus } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) { }
@Get()
getHello(@Req() req: any): any {
console.log(req.authInfo);
const isAuthorized = req.authInfo.checkLocalScope('YourScope');
if (isAuthorized) {
return req.user;
} else {
return new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
// return this.appService.getHello();
}
}
详情请参考this