technoshop

杉並区和泉のソフトウェアハウス、株式会社テラソフトの技術ブログです。主に.NET MVCとKnockoutJSの情報をまとめます。

SimpleMembershipで認証と認可(BootstrapのNabvarにログインメニューも入れてみる)

ザクです。10月になりましたね。食べ物が美味しいです。

.Net MVC4で認証(Authentication)と認可(Authorization)をやるために、SimpleMembershipをプロジェクトに組込しました。結構面倒くさかったですね。しかし、一度、これをやっておけば認証と認可はSimpleMembershipにお任せできるようになります。

SimpleMembershipの素晴らしさを実感するために、コントローラに簡単な修正を加えましょう。

[Authorize]フィルターで簡単ログイン&アクセスコントロール!

試しに既存のHomeを使って特定のアクションを実行するのに認証が必要なようにしてみます。方法は簡単です。コントローラ内でアクセスするのにログインが必要にしたいアクションの真上に[Authorize]フィルターを追加します。

[Authorize]
public ActionResult Contact()
{
    ViewBag.Message = "Your contact page.";

    return View();
}

Contactの上に付けてみました。ビルドしてトップページからリンクをクリックしてみましょう。ログインフォームに遷移しましたね。先の説明の中で作ったシードデータのユーザーを使ったログインします。

f:id:technoshop:20140929102243j:plain

あらあらエラーが出てしまいました。「"WebSecurity.InitializeDatabaseConnection" メソッドを呼び出してから」とあります。そうです、SimpleMembershipが提供している機能(主にWebSecurityクラス)を利用するには、必ず一度WebSecurity.InitializeDatabaseConnectionを実行している必要があるのです。先の説明でプロジェクトから除外したフィルターを覚えているでしょうか?あれがまさしくこれをやるためのものだったのです。あのままフィルターを残しておいても良いのですが、このWebSecurity.InitializeDatabaseConnectionはアプリ起動時に一度実行すれば十分なので、それをやるための別の場所に移動させることにしました。Global.asaxを使います。Application_Startに追加します。

    protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
            WebSecurity.InitializeDatabaseConnection( ←これを追加 
                "DefaultConnection",
                "UserProfile",
                "UserId",
                "UserName", autoCreateTables: true);
        }

「using WebMatrix.WebData;」を追加するのも忘れないでください。ビルドして、再びログインします。画面上の変化はありませんが、今度はエラーを出さずにログインができたようです。Contactにも見れるようになりました。

Bootstrapを使ってログインメニューをかっこ良くする

このままでは、あまりにもアレなので、Bootstrapを使ってログインメニューを作ります。まず、レイアウトにナビゲーションバーを追加します。_Layout.cshtmlファイルを開、class="container"となっているdivを以下のnavタグに置き換えてみてください。(Bootstrap3を使っています)

    <nav class="navbar navbar-default" role="navigation">
        <div class="container-fluid">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="#">Application Name</a>
            </div>         
            <div class="collapse navbar-collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "Index", "Home", null, new { @class = "active" })</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                </ul>
                @Html.Partial("_LoginMenu")
            </div><!--/.nav-collapse -->
        </div>
    </nav>   

_LoginMenuのパーシャルを作ります。プロジェクトの「Views/Shared」フォルダを右クリックして、「_LoginMenu.cshtml」を新規作成してください。中身はこんな感じになります。

<ul class="nav navbar-nav navbar-right">
    <li><a href="#">Today: @DateTime.Now.ToString("M/d/yyyy")</a></li>
    @if (Request.IsAuthenticated) {
    <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">@User.Identity.Name <b class="caret"></b></a> 
              
        <ul class="dropdown-menu" role="menu">
            <li class="divider"></li>
            <li><a href="javascript:document.getElementById('logoutForm').submit()">Logout</a></li>
        </ul>
    </li>     
    } else {
    <li>@Html.ActionLink("Login", "Login", "Account")</li>
    }
</ul>

f:id:technoshop:20140929104551j:plain

いい感じになりました。