1+ //===----------------------------------------------------------------------===//
2+ //
3+ // This source file is part of the Swift OpenAPI Lambda open source project
4+ //
5+ // Copyright (c) 2023 Amazon.com, Inc. or its affiliates
6+ // and the Swift OpenAPI Lambda project authors
7+ // Licensed under Apache License v2.0
8+ //
9+ // See LICENSE.txt for license information
10+ // See CONTRIBUTORS.txt for the list of Swift OpenAPI Lambda project authors
11+ //
12+ // SPDX-License-Identifier: Apache-2.0
13+ //
14+ //===----------------------------------------------------------------------===//
15+
16+ //===----------------------------------------------------------------------===//
17+ //
18+ // This source file is part of the SwiftOpenAPIGenerator open source project
19+ //
20+ // Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
21+ // Licensed under Apache License v2.0
22+ //
23+ // See LICENSE.txt for license information
24+ // See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
25+ //
26+ // SPDX-License-Identifier: Apache-2.0
27+ //
28+ //===----------------------------------------------------------------------===//
29+ import OpenAPIRuntime
30+ import HTTPTypes
31+
32+ /// A server middleware that authenticates the incoming user based on the value of
33+ /// the `Authorization` header field and injects the identifier `User` information
34+ /// into a task local value, allowing the request handler to use it.
35+ package struct AuthenticationServerMiddleware : Sendable {
36+
37+ /// Information about an authenticated user.
38+ package struct User : Hashable {
39+
40+ /// The name of the authenticated user.
41+ package var name : String
42+
43+ /// Creates a new user.
44+ /// - Parameter name: The name of the authenticated user.
45+ package init ( name: String ) { self . name = name }
46+
47+ /// The task local value of the currently authenticated user.
48+ @TaskLocal package static var current : User ?
49+ }
50+
51+ /// The closure that authenticates the user based on the value of the `Authorization`
52+ /// header field.
53+ private let authenticate : @Sendable ( String ) -> User ?
54+
55+ /// Creates a new middleware.
56+ /// - Parameter authenticate: The closure that authenticates the user based on the value
57+ /// of the `Authorization` header field.
58+ package init ( authenticate: @Sendable @escaping ( String ) -> User ? ) { self . authenticate = authenticate }
59+ }
60+
61+ extension AuthenticationServerMiddleware : ServerMiddleware {
62+ package func intercept(
63+ _ request: HTTPRequest ,
64+ body: HTTPBody ? ,
65+ metadata: ServerRequestMetadata ,
66+ operationID: String ,
67+ next: @Sendable ( HTTPRequest, HTTPBody? , ServerRequestMetadata) async throws -> ( HTTPResponse , HTTPBody ? )
68+ ) async throws -> ( HTTPResponse , HTTPBody ? ) {
69+ // Extracts the `Authorization` value, if present.
70+ // If no `Authorization` header field value was provided, no User is injected into
71+ // the task local.
72+ guard let authorizationHeaderFieldValue = request. headerFields [ . authorization] else {
73+ return try await next ( request, body, metadata)
74+ }
75+ // Delegate the authentication logic to the closure.
76+ let user = authenticate ( authorizationHeaderFieldValue)
77+ // Inject the authenticated user into the task local and call the next middleware.
78+ return try await User . $current. withValue ( user) { try await next ( request, body, metadata) }
79+ }
80+ }
0 commit comments