Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
Swift 4.2

Newest Vapor Packages are compatabile now
  • Loading branch information
proggeramlug committed Sep 27, 2018
1 parent 830c838 commit 717a1bc
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM swift:4.1
FROM swift:4.2

ARG ENVIRONMENT
ENV ENVIRONMENT ${ENVIRONMENT:-production}
Expand Down
8 changes: 5 additions & 3 deletions Sources/App/Configuration/configure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ public func configure(
try services.register(jwtProvider)

/// Register routes to the router
let router = EngineRouter.default()
try routes(router)
services.register(router, as: Router.self)
services.register(Router.self) { container -> EngineRouter in
let router = EngineRouter.default()
try routes(router, container)
return router
}

/// Register middleware
var middlewares = MiddlewareConfig() // Create _empty_ middleware config
Expand Down
7 changes: 5 additions & 2 deletions Sources/App/Configuration/router.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import Routing
import Vapor
import JWTMiddleware

/// Register your application's routes here.
///
/// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#routesswift)
public func routes(_ router: Router) throws {
public func routes(_ router: Router, _ container: Container) throws {

// Create a 'health' route useed by AWS to check if the server needs a re-boot.
router.get(any, "users", "health") { _ in
return "all good"
}

try router.register(collection: AuthController())
let jwtService = try container.make(JWTService.self)

try router.register(collection: AuthController(jwtService: jwtService))
try router.register(collection: VersionedCollection())
}
25 changes: 13 additions & 12 deletions Sources/App/Controllers/AuthController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import JWT

/// A route controller that handles user authentication with JWT.
final class AuthController: RouteCollection {
private let jwtService:JWTService

init(jwtService: JWTService) {
self.jwtService = jwtService
}

func boot(router: Router) throws {

let auth = router.grouped(any, "users")
Expand Down Expand Up @@ -131,13 +137,10 @@ final class AuthController: RouteCollection {

/// A route handler that returns a new access and refresh token for the user.
func refreshAccessToken(_ request: Request)throws -> Future<[String: String]> {
let signer = try request.make(JWTService.self)

// Get refresh token from request body and verify it.
let refreshToken = try request.content.syncGet(String.self, at: "refreshToken")
let refreshJWT = try JWT<RefreshToken>(from: refreshToken, verifiedUsing: signer.signer)
try refreshJWT.payload.verify()

let refreshJWT = try JWT<RefreshToken>(from: refreshToken, verifiedUsing: self.jwtService.signer)
try refreshJWT.payload.verify(using: self.jwtService.signer)
// Get the user with the ID that was just fetched.
let userID = refreshJWT.payload.id
let user = User.find(userID, on: request).unwrap(or: Abort(.badRequest, reason: "No user found with ID '\(userID)'."))
Expand All @@ -148,12 +151,12 @@ final class AuthController: RouteCollection {

// Construct the new access token payload
let payload = try App.Payload(user: user)
return try request.payloadData(signer.sign(payload), with: ["userId": "\(user.requireID())"], as: JSON.self).and(result: payload)
return try request.payloadData(self.jwtService.sign(payload), with: ["userId": "\(user.requireID())"], as: JSON.self).and(result: payload)
}.map(to: [String: String].self) { payloadData in
let payload = try payloadData.0.merge(payloadData.1.json())

// Return the signed token with a success status.
let token = try signer.sign(payload)
let token = try self.jwtService.sign(payload)
return ["status": "success", "accessToken": token]
}
}
Expand All @@ -179,15 +182,13 @@ final class AuthController: RouteCollection {
/// The actual authentication is handled by the `JWTAuthenticatableMiddleware`.
/// The request's body should contain an email and a password for authenticating.
func login(_ request: Request)throws -> Future<LoginResponse> {
let signer = try request.make(JWTService.self)

let user = try request.requireAuthenticated(User.self)
let userPayload = try Payload(user: user)

// Create a payload using the standard data
// and the data from the registered `DataService`s
let remotePayload = try request.payloadData(
signer.sign(userPayload),
self.jwtService.sign(userPayload),
with: ["userId": "\(user.requireID())"],
as: JSON.self
)
Expand All @@ -196,8 +197,8 @@ final class AuthController: RouteCollection {
return remotePayload.map(to: LoginResponse.self) { remotePayload in
let payload = try remotePayload.merge(userPayload.json())

let accessToken = try signer.sign(payload)
let refreshToken = try signer.sign(RefreshToken(user: user))
let accessToken = try self.jwtService.sign(payload)
let refreshToken = try self.jwtService.sign(RefreshToken(user: user))

guard user.confirmed else { throw Abort(.badRequest, reason: "User not activated.") }

Expand Down
10 changes: 5 additions & 5 deletions Sources/App/Models/AccessToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ struct Payload: PermissionedUserPayload {
self.id = try user.requireID()
}

func verify() throws {
func verify(using signer: JWTSigner) throws {
let expiration = Date(timeIntervalSince1970: self.exp)
try ExpirationClaim(value: expiration).verify()
try ExpirationClaim(value: expiration).verifyNotExpired()
}
}

Expand All @@ -50,14 +50,14 @@ struct RefreshToken: IdentifiableJWTPayload {
self.exp = now + expiration
}

func verify() throws {
func verify(using signer: JWTSigner) throws {
let expiration = Date(timeIntervalSince1970: self.exp)
try ExpirationClaim(value: expiration).verify()
try ExpirationClaim(value: expiration).verifyNotExpired()
}
}

extension JSON: JWTPayload {
public func verify() throws {
public func verify(using signer: JWTSigner) throws {
// Don't do anything
// We only conform to `JWTPayload`
// so we can sign a JWT with JSON as
Expand Down
1 change: 1 addition & 0 deletions Sources/App/Models/Attribute/Attribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Vapor

/// An attribute for a `User` to store custom data..
final class Attribute: Content, MySQLModel, Migration, Parameter {
static let entity: String = "attributes"

/// The database ID of a class instance.
var id: Int?
Expand Down
1 change: 1 addition & 0 deletions Sources/App/Models/User/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Vapor

/// A generic user that can be conected to any service that uses JWT for authentication.
final class User: Content, MySQLModel, Migration, Parameter {
static let entity: String = "users"

/// The database ID of the class instance.
var id: Int?
Expand Down

0 comments on commit 717a1bc

Please sign in to comment.