Skip to content

Commit b04c9ce

Browse files
authored
Merge pull request #19 from vapor/guard-middleware
redirect middleware
2 parents 8ce4d96 + af34d7a commit b04c9ce

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import HTTP
2+
import Authentication
3+
4+
/// Redirects authenticated requests to a supplied path.
5+
public final class InverseRedirectMiddleware<U: Authenticatable>: Middleware {
6+
/// The path to redirect to
7+
public let path: String
8+
9+
/// Which type of redirect to perform
10+
public let redirectType: RedirectType
11+
12+
/// Create a new inverse redirect middleware.
13+
public init(
14+
_ userType: U.Type = U.self,
15+
path: String,
16+
redirectType: RedirectType = .normal
17+
) {
18+
self.path = path
19+
self.redirectType = redirectType
20+
}
21+
22+
public func respond(to req: Request, chainingTo next: Responder) throws -> Response {
23+
guard !req.auth.isAuthenticated(U.self) else {
24+
return Response(redirect: path, redirectType)
25+
}
26+
27+
return try next.respond(to: req)
28+
}
29+
30+
/// Use this middleware to redirect authenticated
31+
/// away from login pages back to a secure home page.
32+
public static func home(_ userType: U.Type = U.self, path: String = "/") -> InverseRedirectMiddleware {
33+
return InverseRedirectMiddleware(U.self, path: path)
34+
}
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import HTTP
2+
import Authentication
3+
4+
/// Redirects unauthenticated requests to a supplied path.
5+
public final class RedirectMiddleware: Middleware {
6+
/// The path to redirect to
7+
public let path: String
8+
9+
/// Which type of redirect to perform
10+
public let redirectType: RedirectType
11+
12+
/// Create a new redirect middleware.
13+
public init(
14+
path: String,
15+
redirectType: RedirectType = .normal
16+
) {
17+
self.path = path
18+
self.redirectType = redirectType
19+
}
20+
21+
public func respond(to req: Request, chainingTo next: Responder) throws -> Response {
22+
do {
23+
return try next.respond(to: req)
24+
} catch is AuthenticationError {
25+
return Response(redirect: path, redirectType)
26+
}
27+
}
28+
29+
/// Use this middleware to redirect users away from
30+
/// protected content to a login page
31+
public static func login(path: String = "/login") -> RedirectMiddleware {
32+
return RedirectMiddleware(path: path)
33+
}
34+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import XCTest
2+
import Vapor
3+
import HTTP
4+
import AuthProvider
5+
import Authentication
6+
import Testing
7+
8+
class MiddlewareTests: XCTestCase {
9+
override func setUp() {
10+
Testing.onFail = XCTFail
11+
}
12+
13+
/// Test that an unauthenticated request to a secure
14+
/// page gets redirected to the login page.
15+
func testRedirectMiddleware() throws {
16+
let drop = try Droplet()
17+
18+
let redirect = RedirectMiddleware.login()
19+
let auth = TokenAuthenticationMiddleware(TestUser.self)
20+
21+
let protected = drop.grouped([redirect, auth])
22+
protected.get { req in
23+
let user = try req.auth.assertAuthenticated(TestUser.self)
24+
return "Welcome to the dashboard, \(user.name)"
25+
}
26+
27+
try drop.testResponse(to: .get, at: "/")
28+
.assertStatus(is: .seeOther)
29+
.assertHeader("Location", contains: "/login")
30+
}
31+
32+
/// Test that an authenticated request to login
33+
/// gets redirected to the home page.
34+
func testInverseRedirectMiddleware() throws {
35+
let drop = try Droplet()
36+
37+
let redirect = InverseRedirectMiddleware.home(TestUser.self)
38+
let group = drop.grouped([redirect])
39+
group.get("login") { req in
40+
return "Please login"
41+
}
42+
43+
let req = Request.makeTest(method: .get, path: "/login")
44+
let user = TestUser(name: "Foo")
45+
req.auth.authenticate(user)
46+
47+
try drop.testResponse(to: req)
48+
.assertStatus(is: .seeOther)
49+
.assertHeader("Location", contains: "/")
50+
}
51+
52+
static var allTests = [
53+
("testRedirectMiddleware", testRedirectMiddleware),
54+
("testInverseRedirectMiddleware", testInverseRedirectMiddleware)
55+
]
56+
}

0 commit comments

Comments
 (0)