2017-05-31 8 views
0

ファイルをアップロードするためにセットアップされたサーバー側の迅速なプロジェクトがあります。そして、私は、ファイルが有効なログインでのみアクセスできるように、プロジェクトへの認証を試みています。完全な認証とルートを備えたサーバーサイドスウィフト

main.swift

import PerfectLib 
import PerfectHTTP 
import PerfectHTTPServer 

import StORM 
import SQLiteStORM 
import PerfectTurnstileSQLite 
import PerfectRequestLogger 
import TurnstilePerfect 

//StORMdebug = true 

// Used later in script for the Realm and how the user authenticates. 
let pturnstile = TurnstilePerfectRealm() 


// Set the connection vatiable 
//connect = SQLiteConnect("./authdb") 
SQLiteConnector.db = "./authdb" 
RequestLogFile.location = "./http_log.txt" 

// Set up the Authentication table 
let auth = AuthAccount() 
try? auth.setup() 

// Connect the AccessTokenStore 
tokenStore = AccessTokenStore() 
try? tokenStore?.setup() 

//let facebook = Facebook(clientID: "CLIENT_ID", clientSecret: "CLIENT_SECRET") 
//let google = Google(clientID: "CLIENT_ID", clientSecret: "CLIENT_SECRET") 

// Create HTTP server. 
let server = HTTPServer() 

// Register routes and handlers 
let authWebRoutes = makeWebAuthRoutes() 
let authJSONRoutes = makeJSONAuthRoutes("/api/v1") 

// Add the routes to the server. 
server.addRoutes(authWebRoutes) 
server.addRoutes(authJSONRoutes) 

// Adding a test route 
var routes = Routes() 
var postHandle: [[String: Any]] = [[String: Any]]() 
routes.add(method: .get, uri: "/api/v1/test", handler: AuthHandlersJSON.testHandler) 
routes.add(method: .post, uri: "/", handler: { 
    request, response in 

    // Context variable, which also initializes the "files" array 
    var context = ["files":[[String:String]]()] 

    // Process only if request.postFileUploads is populated 
    if let uploads = request.postFileUploads, uploads.count > 0 { 

     // iterate through the file uploads. 
     for upload in uploads { 

      // move file 
      let thisFile = File(upload.tmpFileName) 
      do { 
       let _ = try thisFile.moveTo(path: "./webroot/uploads/\(upload.fileName)", overWrite: true) 
      } catch { 
       print(error) 
      } 
     } 
    } 

    // Inspect the uploads directory contents 
    let d = Dir("./webroot/uploads") 
    do{ 
     try d.forEachEntry(closure: {f in 
      context["files"]?.append(["name":f]) 
     }) 
    } catch { 
     print(error) 
    } 


    // Render the Mustache template, with context. 
    response.render(template: "index", context: context) 
    response.completed() 
}) 
routes.add(method: .get, uri: "/", handler: { 
    request, response in 

    // Context variable, which also initializes the "files" array 
    var context = ["files":[[String:String]]()] 

    // Process only if request.postFileUploads is populated 
    if let uploads = request.postFileUploads, uploads.count > 0 { 

     // iterate through the file uploads. 
     for upload in uploads { 

      // move file 
      let thisFile = File(upload.tmpFileName) 
      do { 
       let _ = try thisFile.moveTo(path: "./webroot/uploads/\(upload.fileName)", overWrite: true) 
      } catch { 
       print(error) 
      } 
     } 
    } 

    // Inspect the uploads directory contents 
    let d = Dir("./webroot/uploads") 
    do{ 
     try d.forEachEntry(closure: {f in 
      context["files"]?.append(["name":f]) 
     }) 
    } catch { 
     print(error) 
    } 

    var resp = [String: String]() 
    resp["authenticated"] = "AUTHED: \(request.user.authenticated)" 
    // Render the Mustache template, with context. 
    response.render(template: "index", context: resp) 
    response.completed() 
}) 
routes.add(method: .get, uri: "/**", handler: try PerfectHTTPServer.HTTPHandler.staticFiles(data: ["documentRoot":"./webroot", 
                        "allowResponseFilters":true])) 


// An example route where authentication will be enforced 
routes.add(method: .get, uri: "/api/v1/check", handler: { 
    request, response in 
    response.setHeader(.contentType, value: "application/json") 

    var resp = [String: String]() 
    resp["authenticated"] = "AUTHED: \(request.user.authenticated)" 
    resp["authDetails"] = "DETAILS: \(String(describing: request.user.authDetails))" 

    do { 
     try response.setBody(json: resp) 
    } catch { 
     print(error) 
    } 
    response.completed() 
}) 


// An example route where auth will not be enforced 
routes.add(method: .get, uri: "/api/v1/nocheck", handler: { 
    request, response in 
    response.setHeader(.contentType, value: "application/json") 

    var resp = [String: String]() 
    resp["authenticated"] = "AUTHED: \(request.user.authenticated)" 
    resp["authDetails"] = "DETAILS: \(String(describing: request.user.authDetails))" 

    do { 
     try response.setBody(json: resp) 
    } catch { 
     print(error) 
    } 
    response.completed() 
}) 



// Add the routes to the server. 
server.addRoutes(routes) 


// Setup logging 
let myLogger = RequestLogger() 

// add routes to be checked for auth 
var authenticationConfig = AuthenticationConfig() 
authenticationConfig.include("/api/v1/check") 
authenticationConfig.exclude("/api/v1/login") 
authenticationConfig.exclude("/api/v1/register") 

let authFilter = AuthFilter(authenticationConfig) 

// Note that order matters when the filters are of the same priority level 
server.setRequestFilters([pturnstile.requestFilter]) 
server.setResponseFilters([pturnstile.responseFilter]) 

server.setRequestFilters([(authFilter, .high)]) 

server.setRequestFilters([(myLogger, .high)]) 
server.setResponseFilters([(myLogger, .low)]) 

// Set a listen port of 8181 
server.serverPort = 8181 

// Where to serve static files from 
server.documentRoot = "./webroot" 

do { 
    // Launch the HTTP server. 
    try server.start() 
} catch PerfectError.networkError(let err, let msg) { 
    print("Network error thrown: \(err) \(msg)") 
} 

私は、コンテキストを変更した場合:私も成功したログイン後に記録されておりませんのようなコンテキストに私は、ループ内で動けなくなります。コンテキストを変更した場合:respするには、常にログインしている状態になってしまい、ファイルが表示されません。

var resp = [String: String]() 
    resp["authenticated"] = "AUTHED: \(request.user.authenticated)" 
    // Render the Mustache template, with context. 
    response.render(template: "index", context: resp) 
    response.completed() 

index.mustache

{{>header}} 

{{^authenticated}} 
<h1>Hi! Sign up today!</h1> 
{{/authenticated}} 
{{#authenticated}} 
<h1>Hi! {{username}}</h1> 
<p>Your ID is: <code>{{accountID}}</code></p> 
<h2>File uploads</h2> 
<form method="POST" enctype="multipart/form-data" action=""> 
File to upload: <input type="file" name="fileup"><br> 
<input type="submit" value="Upload files now."> 
</form> 

<h3>Files:</h3> 
{{#files}}<a href="/uploads/{{name}}">{{name}}</a><br>{{/files}} 
{{/authenticated}} 



{{>footer}} 

UPDATEは

私は私がそれを望むように作業部位を有するに近いと思います。コードブローは私が行った変更と私が来るために必要な新しいハードルを示しています。どのように同じで2つの異なるコンテキストを使用するのですかrender

routes.add(method: .get, uri: "/", handler: { request, response in 

    if request.user.authenticated == true { 
     guard let accountID = request.user.authDetails?.account.uniqueID else { return } 

     do { 
      let newDir = Dir("./webroot/uploads/\(String(describing: accountID))") 
      let _ = try newDir.create() 
     } catch { 

     } 
     // Context variable, which also initializes the "files" array 
     var context = ["files":[[String:String]]()] 

     // Process only if request.postFileUploads is populated 
     if let uploads = request.postFileUploads, uploads.count > 0 { 

      // iterate through the file uploads. 
      for upload in uploads { 

       // move file 
       let thisFile = File(upload.tmpFileName) 
       do { 
        let _ = try thisFile.moveTo(path: "./webroot/uploads/\(String(describing: accountID))/\(upload.fileName)", overWrite: true) 
       } catch { 
        print(error) 
       } 
      } 
     } 

     // Inspect the uploads directory contents 
     let d = Dir("./webroot/uploads/\(String(describing: accountID))") 
     do{ 
      try d.forEachEntry(closure: {f in 
       context["files"]?.append(["name":f]) 
      }) 
     } catch { 
      print(error) 
     } 
     let setID = [["accountID": accountID]] 
     var dic = [String: String]() 
     for item in setID { 
      for (kind, value) in item { 
       dic.updateValue(value, forKey: kind) 
      } 
     } 

     var context1 = ["files":String()] 
     context1.updateValue(accountID, forKey: "accountID") 
     // Render the Mustache template, with context. 
     response.render(template: "loggedin", context: context) // I only get this context info. 
     response.render(template: "loggedin", context: context1) // This is ignored unless I comment out the line above. 
     response.completed() 

    } else { 
     response.render(template: "index") 
     response.completed() 

    } 
}) 

このセクションのコードも変更されました。

var authenticationConfig = AuthenticationConfig() 
authenticationConfig.include("/api/v1/check") 
authenticationConfig.include("/loggedin") // Added this line 
authenticationConfig.exclude("/api/v1/login") 
authenticationConfig.exclude("/api/v1/register") 
+0

は、あなたがここにデモを見てきましたか? https://github.com/PerfectExamples/Perfect-Turnstile-SQLite-Demo良い出発点になるかもしれません。私はあなたがいくつかのコンポーネントを欠いていると思うが、あなたの構造を見ずに、ごめんなさい。 Thx、Jono –

答えて

0

これはPerfect-Turnstile-SQLite-Demoとこのプロジェクトの一部であるFile-Uploadsに基づいています。目的は、ユーザーのログインに基づいて、ユーザーがファイルをアップロードするためのプライベートディレクトリを作成するSwift Server Sideアプリケーションを作成することでした。

main.swift

// 
// main.swift 
// PerfectTurnstileSQLiteDemo 
// 
// Created by Jonathan Guthrie on 2016-10-11. 
// Copyright (C) 2015 PerfectlySoft, Inc. 
// 
//===----------------------------------------------------------------------===// 
// 
// This source file is part of the Perfect.org open source project 
// 
// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors 
// Licensed under Apache License v2.0 
// 
// See http://perfect.org/licensing.html for license information 
// 
//===----------------------------------------------------------------------===// 
// 

import PerfectLib 
import PerfectHTTP 
import PerfectHTTPServer 

import StORM 
import SQLiteStORM 
import PerfectTurnstileSQLite 
import PerfectRequestLogger 
import TurnstilePerfect 

//StORMdebug = true 

// Used later in script for the Realm and how the user authenticates. 
let pturnstile = TurnstilePerfectRealm() 


// Set the connection vatiable 
//connect = SQLiteConnect("./authdb") 
SQLiteConnector.db = "./authdb" 
RequestLogFile.location = "./http_log.txt" 


// Set up the Authentication table 
let auth = AuthAccount() 
try? auth.setup() 

// Connect the AccessTokenStore 
tokenStore = AccessTokenStore() 
try? tokenStore?.setup() 

//let facebook = Facebook(clientID: "CLIENT_ID", clientSecret: "CLIENT_SECRET") 
//let google = Google(clientID: "CLIENT_ID", clientSecret: "CLIENT_SECRET") 

// Create HTTP server. 
let server = HTTPServer() 

// Register routes and handlers 
let authWebRoutes = makeWebAuthRoutes() 
let authJSONRoutes = makeJSONAuthRoutes("/api/v1") 

// Add the routes to the server. 
server.addRoutes(authWebRoutes) 
server.addRoutes(authJSONRoutes) 

// Adding a test route 
var routes = Routes() 
routes.add(method: .get, uri: "/api/v1/test", handler: AuthHandlersJSON.testHandler) 
routes.add(method: .post, uri: "/", handler: { 
    request, response in 


    if request.user.authenticated == true { 
     guard let accountID = request.user.authDetails?.account.uniqueID else { return } 

     do { 
      let newDir = Dir("./webroot/uploads/\(String(describing: accountID))") 
      let _ = try newDir.create() 
     } catch { 

     } 
     // Context variable, which also initializes the "files" array 
     var context = ["files":[[String:String]]()] 

     // Process only if request.postFileUploads is populated 
     if let uploads = request.postFileUploads, uploads.count > 0 { 

      // iterate through the file uploads. 
      for upload in uploads { 

       // move file 
       let thisFile = File(upload.tmpFileName) 
       do { 
        let _ = try thisFile.moveTo(path: "./webroot/uploads/\(String(describing: accountID))/\(upload.fileName)", overWrite: true) 
       } catch { 
        print(error) 
       } 
      } 
     } 

     // Inspect the uploads directory contents 
     let d = Dir("./webroot/uploads/\(String(describing: accountID))") 
     do{ 
      try d.forEachEntry(closure: {f in 
       context["files"]?.append(["name":f]) 
      }) 
     } catch { 
      print(error) 
     } 

     context["files"]?.append(["aID":accountID]) 
     // Render the Mustache template, with context. 
     response.render(template: "loggedin", context: context) 
     response.completed() 

    } else { 
     response.render(template: "index") 
     response.completed() 

    } 
}) 
routes.add(method: .get, uri: "/", handler: { request, response in 

    if request.user.authenticated == true { 
     guard let accountID = request.user.authDetails?.account.uniqueID else { return } 

     do { 
      let newDir = Dir("./webroot/uploads/\(String(describing: accountID))") 
      let _ = try newDir.create() 
     } catch { 

     } 
     // Context variable, which also initializes the "files" array 
     var context = ["files":[[String:String]]()] 

     // Process only if request.postFileUploads is populated 
     if let uploads = request.postFileUploads, uploads.count > 0 { 

      // iterate through the file uploads. 
      for upload in uploads { 

       // move file 
       let thisFile = File(upload.tmpFileName) 
       do { 
        let _ = try thisFile.moveTo(path: "./webroot/uploads/\(String(describing: accountID))/\(upload.fileName)", overWrite: true) 
       } catch { 
        print(error) 
       } 
      } 
     } 

     // Inspect the uploads directory contents 
     let d = Dir("./webroot/uploads/\(String(describing: accountID))") 
     do{ 
      try d.forEachEntry(closure: {f in 
       context["files"]?.append(["name":f]) 
      }) 
     } catch { 
      print(error) 
     } 

     context["files"]?.append(["aID":accountID]) 
     // Render the Mustache template, with context. 
     response.render(template: "loggedin", context: context) 
     response.completed() 

    } else { 
     response.render(template: "index") 
     response.completed() 

    } 
}) 
routes.add(method: .get, uri: "/**", handler: try PerfectHTTPServer.HTTPHandler.staticFiles(data: ["documentRoot":"./webroot", "allowResponseFilters":true])) 

// An example route where authentication will be enforced 
routes.add(method: .get, uri: "/api/v1/check", handler: { 
    request, response in 
    response.setHeader(.contentType, value: "application/json") 

    var resp = [String: String]() 
    resp["authenticated"] = "AUTHED: \(request.user.authenticated)" 
    resp["authDetails"] = "DETAILS: \(String(describing: request.user.authDetails))" 

    do { 
     try response.setBody(json: resp) 
    } catch { 
     print(error) 
    } 
    response.completed() 
}) 


// An example route where auth will not be enforced 
routes.add(method: .get, uri: "/api/v1/nocheck", handler: { 
    request, response in 
    response.setHeader(.contentType, value: "application/json") 

    var resp = [String: String]() 
    resp["authenticated"] = "AUTHED: \(request.user.authenticated)" 
    resp["authDetails"] = "DETAILS: \(String(describing: request.user.authDetails))" 

    do { 
     try response.setBody(json: resp) 
    } catch { 
     print(error) 
    } 
    response.completed() 
}) 



// Add the routes to the server. 
server.addRoutes(routes) 

// Setup logging 
let myLogger = RequestLogger() 

// add routes to be checked for auth 
var authenticationConfig = AuthenticationConfig() 
authenticationConfig.include("/api/v1/check") 
authenticationConfig.exclude("/api/v1/login") 
authenticationConfig.exclude("/api/v1/register") 

let authFilter = AuthFilter(authenticationConfig) 

// Note that order matters when the filters are of the same priority level 
server.setRequestFilters([pturnstile.requestFilter]) 
server.setResponseFilters([pturnstile.responseFilter]) 

server.setRequestFilters([(authFilter, .high)]) 

server.setRequestFilters([(myLogger, .high)]) 
server.setResponseFilters([(myLogger, .low)]) 

// Set a listen port of 8181 
server.serverPort = 8181 

// Where to serve static files from 
server.documentRoot = "./webroot" 

do { 
    // Launch the HTTP server. 
    try server.start() 
} catch PerfectError.networkError(let err, let msg) { 
    print("Network error thrown: \(err) \(msg)") 
} 

header.mustache

<html> 
    <head> 
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> 
    <link href="/styles/jumbotron-narrow.css" rel="stylesheet"> 
    <title>{{title}}</title> 
    </head> 
    <body> 
    <div class="container"> 
    <div class="header clearfix"> 
     <nav> 
     <ul class="nav nav-pills pull-right"> 
      {{^authenticated}} 
      <li role="presentation"><a href="/login">Log In</a></li> 
      {{/authenticated}} 
      {{#authenticated}} 
      <li role="presentation"><a href="javascript:;" onclick="var f=document.createElement('form');f.method='POST';f.action='/logout';f.submit();">Logout</a></li> 
      {{/authenticated}} 
     </ul> 
     </nav> 
<img id="logo" src="/images/perfect-logo-2-0.png" width="176" height="58" alt="Perfect Logo"> 

     <h3 class="text-muted"><a href="/">Perfect Swift Secure File Upload</a></h3> 
    </div> 
    {{#flash}} 
    <div class="alert alert-danger" role="alert"> 
     <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> 
     <span class="sr-only">Error:</span> 
     {{flash}} 
    </div> 
    {{/flash}} 


index.mustache

{{>header}} 

{{^authenticated}} 
<h1>Hi! Sign up today!</h1> 
{{/authenticated}} 

{{>footer}} 

loggedin.mustache

{{>header2}} 


<h2>File uploads</h2> 
<form method="POST" enctype="multipart/form-data" action=""> 
File to upload: <input type="file" name="fileup"><br> 
<input type="submit" value="Upload files now."> 
</form> 
<code>{{#files}}{{aID}}{{/files}}</code> 
<h3>Files:</h3> 
{{#files}}<a href="/uploads/{{#files}}{{aID}}{{/files}}/{{name}}">{{name}}</a><br>{{/files}} 
{{>footer}} 
1

次のセクションを見ている場合:

var authenticationConfig = AuthenticationConfig() 
authenticationConfig.include("/api/v1/check") 
authenticationConfig.exclude("/api/v1/login") 
authenticationConfig.exclude("/api/v1/register") 

をあなたが積極的に含めるか、認証状態のチェックを除外することができる場所です。

認証チェックから除外するルートには、常にホームルートとログイン/レジスタが必要です。次に、経路を具体的に含めるか、ワイルドカードを使用することができます。

+0

私の質問に追加した更新を見てください。 – MwcsMac

関連する問題