vibe-dに関する私のブログ、パート1:暗号化を使用したシンプルなWebアプリケーション

こんにちは、Habr! あなた自身、隣人、または彼女の犬のためにサイトを作りたいと長い間望んでいたが、まだそれをしていないなら、この記事はあなたのためです! このシリーズの記事では、例として単純なブログを使用してサイトを作成するためにバイブで作業する基本を紹介します。
最初の部分では、基本的なポイントを分析し、結果のアプリケーションに暗号化を追加します。


0.最初から始めましょう


  1. dmdをインストールする
  2. ダブをインストールする
  3. 次のコマンドでvibeを使用してプロジェクトを作成します
    mkdir yourblogname
    cd yourblogname
    dub init -t vibe.d
    作成されたアプリケーションに関するダブの追加質問が送られます。 ほとんどのフィールドにはデフォルト値がありますが、jsonよりも読みやすく、シンプルであり、オプションも同じであるため、sdl形式を選択することをお勧めします。

1.シンプルなWebアプリケーション


そのため、すでにLudwigのブランクがあり、それを拡張する必要があります。 最初に行うことは、アプリケーションのクラスを作成し、いくつかのページを追加することです。


 import vibe.d; shared static this() { auto settings = new HTTPServerSettings; settings.port = 8080; settings.bindAddresses = ["::1", "127.0.0.1"]; auto router = new URLRouter; //       router.registerWebInterface(new MyBlog); //    router.rebuild(); //     =) listenHTTP(settings, router); //      } class MyBlog { @path("/") void getHome(scope HTTPServerRequest req, scope HTTPServerResponse res) { res.writeBody("Hello, World! <a href='/page2'>go to page2</a>", "text/html; charset=UTF-8"); } void getPage2(scope HTTPServerRequest req, scope HTTPServerResponse res) { res.writeBody("Page2 <a href='/'>go to index</a>", "text/html; charset=UTF-8"); } } 

ご覧のとおり、 getHomeメソッドにはUDA @path("/")があり、これがルートページであることを示しています。 UDA-ユーザー定義属性-ユーザーが宣言した属性。 実際、これらは言語のオブジェクトです:列挙型、構造体、単純なデータ型。 UDAを持つエンティティを使用して属性の存在とそのを確認し、UDAでマークされたクラス/構造内のすべてのフィールドとメソッドを取得することもできます。 この場合、vibeはこれを使用して宛先コードを作成します。 getPage2メソッドは命名規則を使用 、パスhttp://127.0.0.1:8080/page2沿ってgetリクエストで実行しhttp://127.0.0.1:8080/page2@propertyメソッドも同じように動作します。 メソッドのシグネチャはテンプレートのhello関数と変わらないため、ページの本文を手で記述します。 面倒ではなく、ビューをviewsフォルダに追加し、すぐに心に追加します。


いくつかのファイルを作成しましょう:


ビュー/ layout.dt

サイトのすべてのページのテンプレート。


 doctype html html head //   head block head //    title   ,      head title #{title} body header //      div,    '<div class="mrow">' .mrow //    views/header.dt include header main .mrow //   main block main footer .mrow //  views/footer.dt include footer 

コメントのインデントは、ブロックのインデントに対応する必要があります。 コメントは結果のhtmlに分類されます。必要ない場合は// - (マイナス記号付き)を使用してください。


ビュー/ header.dt

サイトヘッダーがあります


 div   

ビュー/ footer.dt

地下室があります


 div ,    

ビュー/ index.dt

メインページ、最初の行は、どのテンプレートを展開するかを示します(同じフォルダ内にあり、 .dt拡張子がないため、パスはありませ.dt


 extends layout block head //       ,       //    ,  D ,              - auto title = ""; block main //     - html,     div  a(href="/page2")    

ビュー/ page2.dt

2番目のページはメインに似ています


 extends layout block head - auto title = " "; block main div   2 a(href="/")   

ブログのコードを修正します


 class MyBlog { @path("/") void getHome() { render!("index.dt"); } void getPage2() { render!("page2.dt"); } } 

簡潔になり、回答の本文を直接書く必要がなくなりました。 スタイルを追加!


public / style.css
 * { margin: 0; padding: 0; } body { font-family: sans-serif; font-size: 13px; text-align: center; width: 100%; } .mrow { margin: 0 auto; width: 1170px; text-align: left; } header { height: 60px; width: 100%; background: #e2e2e2; border-top: none; border-right: none; border-left: none; border-bottom: 1px solid; border-radius: 0; border-color: #aaa; margin-bottom: 20px; font-size: 24px; } header div { padding-top: 10px; } main { margin-top: 10px; } footer { height: 60px; width: 100%; background: #333; color: #bbb; position: absolute; margin-top: 20px; padding: 0; bottom: inherit; border-top: 2px solid #888; } footer div { padding-top: 10px; } 

アプリケーションで静的ファイルの配布を有効にする必要があります


 shared static this() { ... router.get("*", serveStaticFiles("public/")); ... } 

最後に、 layout.dt先頭にスタイルを追加します


 ... html head link(rel="stylesheet", href="style.css") ... 

組み立てて起動すると、次のようになります。




そうではありませんが、 私の目が落ちないことと、これで作業することがより快適になることを願っています


2.安全にしましょう


私たちには何らかの基盤がありますが、今はさらなる開発について考える時です。 そして、機能を追加する前に、セキュリティを管理します。暗号化を追加します。 たとえば 、証明書の作成に関する多くの情報を見つけることができます。 説明のない主な手順は次のとおりです。


ルートキー

openssl genrsa -out rootCA.key 2048


ルート証明書

openssl req -x509 -new -key rootCA.key -days 9999 -out rootCA.crt
質問への回答は重要ではありません。ブラウザが彼を信頼するようにします)


別のキー

openssl genrsa -out server.key 2048


証明書要求(ドメイン名を指定することが重要です)

openssl req -new -key server.key -out server.csr


新しい証明書に署名する

openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 9998
ブラウザにrootCA.crtを追加し、 rootCA.key秘密にします。


次に、アプリケーションで暗号化を有効にします。


 shared static this() { ... settings.tlsContext = createTLSContext(TLSContextKind.server); settings.tlsContext.useCertificateChainFile("server.crt"); settings.tlsContext.usePrivateKeyFile("server.key"); ... } 

これで、すべてを正しく行った場合、サイトはhttp経由でアクセスできなくなり、質問なしでhttps経由でアクセスできるようになりhttps


3.最も単純な承認


まず、アプリケーションでセッションを作成します。


 shared static this() { ... settings.sessionStore = new MemorySessionStore; ... } 

いくつかのコードを追加します。 クラスの外部には、セッション変数のタイプがあります。


 struct UserSettings { bool loggedIn = false; string email; } 

複雑な認識のためには、おそらく新しいクラス全体を表示する方が良いでしょう。


 class MyBlog { mixin PrivateAccessProxy; private SessionVar!(UserSettings, "settings") userSettings; //   //   _error        @path("/") void getHome(string _error) { auto error = _error; auto settings = userSettings; render!("index.dt", settings, error); } /+ @errorDisplay ,         msg   getHome,    _error,           @auth  ,    ,     ,   ,   auth, ,  ,      ,   ,     email  +/ @auth @errorDisplay!getHome void getWritepost(string _email) { auto email = _email; render!("writepost.dt", email); } // ValidEmail     string,      @errorDisplay!getHome void postLogin(ValidEmail email, string pass) { enforce(pass == "secret", " "); //       userSettings = UserSettings(true, email); //            redirect("./"); } void postLogout(scope HTTPServerResponse res) { userSettings = UserSettings.init; res.terminateSession(); redirect("./"); } private: /+       ensureAuth,        ensureAuth   _email   +/ enum auth = before!ensureAuth("_email"); /+      ,    ,  email  +/ string ensureAuth(scope HTTPServerRequest req, scope HTTPServerResponse res) { if (!userSettings.loggedIn) redirect("/"); return userSettings.email; } } 

クラスのすべてのパブリックメソッドはルーティングに分類されるため、 ensureAuth privateとして作成されます。 同時に、バイブは@authでマークされたメソッドの前にこのメソッドを呼び出すためにこのメソッドについて知る必要があるため、 mixin PrivateAccessProxyを使用する必要があります。 @auth属性は、フックとして機能するbeforeテンプレートを使用して作成され、マークされた関数の前に指定された関数を呼び出し、フック関数の結果を引数として渡します。 @afterもあります。これは、関数を強制的にafterに実行し、フラグ付きの結果を引数として受け入れるためにフック関数を必要とします。 残念ながら、vibe Webサイトにはドキュメントが見つかりませんでしたが、コードにはこれらのポイントに関するドキュメントがあります。 また、page2メソッドの名前を変更(削除)しました。 GetWritepostはそれを置き換え、新しいレコードを作成するためのページを返します。


残りのファイルもわずかに変更する必要があります。



 extends layout block head - auto title = " "; block main div    #{email} form#postform(action="/posts", method="POST") div  input(class="from-control", name="title") div  textarea(class="form-contorl", name="text") div button(type="submit")  


これで、ログインできるサイトがあり、ログインしていないとアクセスできないページ(writepost)があります。


4.最も単純なブログエントリ


記事は非常に膨大であることが判明しましたが、何らかの論理的なコンマに持っていきたいです)
新しい記事のレコードを通常のクラスフィールドに追加すると、フィールドタイプは構造の配列になります


 struct Post { string author; string title; string text; } 

この配列をクラスに追加し、パラメーターでgetHomeメソッドのrender関数にgetHome 、これらの投稿を配列に書き込むメソッドを追加します。


 class MyBlog { ... public: Post[] posts; @path("/") void getHome(string _error) { ... render!("index.dt", posts, settings, error); } ... //        getWritepost @auth @errorDisplay!getWritepost void postPosts(string title, string text, string _email) { posts ~= Post(_email, title, text); redirect("./"); } ... } 

注意してください-メソッドパラメータの名前はフォームフィールドの名前と一致する必要があります! 主な変更は残ります。これにより、投稿を確認できます。 views/index.dt 、エントリ「Content」をコードviews/index.dt置き換えます


  ... - if (!settings.loggedIn) include logindesk - else - foreach(post; posts) div.post div.title #{post.title} div.text #{post.text} div.author #{post.author} 

ここまでで、次のようなアプリケーションをすでに作成しているはずです。



次のようになりました。




この部分のソースコードはこちらです。


次のパートでは、mongoの使用方法、投稿用ページの作成方法(URLに投稿のインデックスまたは名前が含まれる)、およびコメントについて説明します。


完全に明確ではなかったとコメントに書いてください。この部分を完成させてうれしいです。



Source: https://habr.com/ru/post/J310436/


All Articles