Sicherheit
Standardmäßig können alle RPC-Funktionen von jedem Client aufgerufen werden, und die Peer-to-Peer-Kommunikation ist aktiviert. Um präzise zu steuern, welcher Client was darf, können Sie die Klasse RpcKernelSecurity
überschreiben.
import { RpcKernelSecurity, Session, RpcControllerAccess } from '@deepkit/type'; //enthält Standardimplementierungen class MyKernelSecurity extends RpcKernelSecurity { async hasControllerAccess(session: Session, controllerAccess: RpcControllerAccess): Promise<boolean> { return true; } async isAllowedToRegisterAsPeer(session: Session, peerId: string): Promise<boolean> { return true; } async isAllowedToSendToPeer(session: Session, peerId: string): Promise<boolean> { return true; } async authenticate(token: any): Promise<Session> { throw new Error('Authentication not implemented'); } transformError(err: Error) { return err; } }
Um dies zu verwenden, übergeben Sie den Provider an den RpcKernel
:
const kernel = new RpcKernel([{provide: RpcKernelSecurity, useClass: MyKernelSecurity, scope: 'rpc'}]);
Oder überschreiben Sie im Fall einer Deepkit-App die Klasse RpcKernelSecurity
mit einem Provider in der App:
import { App } from '@deepkit/type'; import { RpcKernelSecurity } from '@deepkit/rpc'; import { FrameworkModule } from '@deepkit/framework'; new App({ controllers: [MyRpcController], providers: [ {provide: RpcKernelSecurity, useClass: MyRpcKernelSecurity, scope: 'rpc'} ], imports: [new FrameworkModule] }).run();
Authentifizierung / Session
Standardmäßig ist das Session
-Objekt eine anonyme Session, d. h. der Client hat sich nicht authentifiziert. Wenn der Client sich authentifizieren möchte, wird die Methode authenticate
aufgerufen. Das von der Methode authenticate
empfangene Token kommt vom Client und kann jeden beliebigen Wert haben.
Sobald der Client ein Token setzt, wird die Authentifizierung ausgeführt, wenn die erste RPC-Funktion aufgerufen wird oder wenn client.connect()
manuell aufgerufen wird.
const client = new RpcWebSocketClient('localhost:8081'); client.token.set('123456789'); const controller = client.controller<Controller>('/main');
In diesem Fall erhält RpcKernelSecurity.authenticate
das Token 123456789
und kann entsprechend eine andere Session zurückgeben. Die zurückgegebene Session wird dann an alle anderen Methoden wie hasControllerAccess
weitergegeben.
import { Session, RpcKernelSecurity } from '@deepkit/rpc'; class UserSession extends Session { } class MyKernelSecurity extends RpcKernelSecurity { async hasControllerAccess(session: Session, controllerAccess: RpcControllerAccess): Promise<boolean> { if (controllerAccess.controllerClassType instanceof MySecureController) { //MySecureController erfordert UserSession return session instanceof UserSession; } return true; } async authenticate(token: any): Promise<Session> { if (token === '123456789') { //Benutzername kann eine ID oder ein Benutzername sein return new UserSession('username', token); } throw new Error('Authentication failed'); } }
Controller-Zugriff
Die Methode hasControllerAccess
bestimmt, ob ein Client eine bestimmte RPC-Funktion ausführen darf. Diese Methode wird bei jedem Aufruf einer RPC-Funktion ausgeführt. Gibt sie false
zurück, wird der Zugriff verweigert und beim Client ein Fehler ausgelöst.
Das RpcControllerAccess
enthält wertvolle Informationen über die RPC-Funktion:
interface RpcControllerAccess { controllerName: string; controllerClassType: ClassType; actionName: string; actionGroups: string[]; actionData: { [name: string]: any }; }
Gruppen und zusätzliche Daten können über den Decorator @rpc.action()
geändert werden:
class Controller { @rpc.action().group('secret').data('role', 'admin') saveUser(user: User): void { } } class MyKernelSecurity extends RpcKernelSecurity { async hasControllerAccess(session: Session, controllerAccess: RpcControllerAccess): Promise<boolean> { if (controllerAccess.actionGroups.includes('secret')) { if (session instanceof UserSession) { //todo: prüfen return session.username === 'admin'; } return false; } return true; } }