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