Node.js mit TSOA und Authentifizierung - (Teil 4) Header-Validierung in der AuthMiddleware

Wir widmen uns der Authentifizierungsmiddleware. Dabei überprüfen wir den Request-Header und behandeln fehlende oder falsche Informationen. Für einen solchen Problemfall erstellen wir die passende Fehlerbehandlung. Los geht’s!

3 Minuten

In diesem Artikel widme ich mich der Überprüfung des eingehenden Requests. Im Fehlerfall – das bedeutet, dass weder ein Authorization-Header noch ein syntaktisch korrekter Header geliefert wurde – soll die Antwort der Applikation „StatusCode 401 Unauthenticated“ lauten. Bevor wir anfangen, empfiehlt es sich, die Vorgänger der Artikelserie zu lesen:

Vorbereitung der Fehlerklasse

Die dazu notwendigen Schritte habe ich bereits in einem vergangenen Artikel beschrieben: Node.js und meine Base-Error-Klasse. Von dieser Base-Error-Klasse leiten wir unseren UnauthenticatedError ab. Wenn du die Schritte aus dem Artikel vollzogen hast, solltest du folgende Ergebnisse vorweisen können:

  • Eine neue BaseError-Klasse.
  • Eine Datei StringUtils mit einer toString-Funktion und der Error-Prototype-Definition für toJSON.
  • Das NPM-Paket flatted installiert haben.

Als Nächstes erstellen wir den Unauthenticated-Error mit dem StatusCode 401. Dieser Fehler besagt, dass wir nicht feststellen konnten, ob der Aufruf der ist, der vorzugeben scheint. Dies steht im Gegensatz zum UnauthorizedError: Hierbei ist der Zugriff für die verifizierte Person nicht gewährt.

import BaseError, { BaseErrorOptions } from '@/errors/BaseError'

class UnauthenticatedError extends BaseError {  
  constructor(options: BaseErrorOptions) {  
    const { detail = 'Unauthenticated', cause } = options  
    super({ detail, cause, statusCode: 401 })  
  }  

  public toJSON() {  
    return super.toJSON()  
  }  

  public toString() {  
    return JSON.stringify(this.toJSON())  
  }  
}

export default UnauthenticatedError

Überprüfung des Authorization-Headers

Jetzt widmen wir uns der AuthMiddleware. Wir erstellen eine validateHeader-Funktion, die den Header prüft und den Token daraus extrahiert. Hierbei ist es wichtig zu betonen, dass wir keinen Error werfen dürfen, sondern einen Promise.reject() aufrufen. Ansonsten brechen wir aus der Express-Middleware aus.

import { Request } from 'express'  
import UnauthenticatedError from '@/errors/UnauthenticatedError'  

type ValidateHeaderSucceed = {  
  isValid: true  
  bearerToken: string  
}  
type ValidateHeaderFailed = {  
  isValid: false  
  error: UnauthenticatedError  
}  
type ValidateHeaderResult = ValidateHeaderSucceed | ValidateHeaderFailed  


const validateHeader = (request: Request): ValidateHeaderResult => {  
  // look up header for authorization  
  const authHeader = request.headers.authorization  

  // validate authorization header  
  if (!authHeader) {  
    return {  
      isValid: false,  
      error: new UnauthenticatedError({ detail: 'No authorization header provided' }),  
    }  
  }  

  if (!authHeader.startsWith('Bearer ')) {  
    return {  
      isValid: false,  
      error: new UnauthenticatedError({ detail: 'No bearer token provided' }),  
    }  
  }  

  const bearerToken = authHeader.split(' ')[1]  

  if (!bearerToken) {  
    return {  
      isValid: false,  
      error: new UnauthenticatedError({ detail: 'No bearer token provided' }),  
    }  
  }  

  return {  
    isValid: true,  
    bearerToken,  
  }  
}

Die Einbindung erfolgt in der AuthMiddleware, in der wir im Fehlerfall Promise.reject aufrufen.

const expressAuthentication = (  
  request: Request,  
  securityName: string,  
  requiredScopes?: string[],  
): Promise<AuthResultType> => {  
  const validateHeaderResult = validateHeader(request)  

  if (!validateHeaderResult.isValid) {  
    console.log(`[AuthMiddleware::${securityName}] Failed due to: ${validateHeaderResult.error.message}`)  
    return Promise.reject(validateHeaderResult.error)  
  }  

  // ... here we will check the token
}

Fazit

An dieser Stelle haben wir es geschafft. Wir prüfen, ob ein eingehender Request den Authorization-Header gesetzt hat. Damit ist der erste Schritt zur Authentifizierung geschafft. Als Nächstes gilt es, das Token zu prüfen. Vorher will ich mich jedoch um das Promise.reject kümmern. Dazu benötigen wir eine Error-Middleware, die solche Fehler in eine Standardantwort übersetzt.

call to action background image

Abonniere meinen Newsletter

Erhalte einmal im Monat Nachrichten aus den Bereichen Softwareentwicklung und Kommunikation gespikt mit Buch- und Linkempfehlungen.