【ASP.NET】WEB用のオシャレなログイン画面を作る

# はじめに
最近、Webアプリケーションを作成する機会がありました。これまでもWEBアプリケーションは改修作業による部分変更はあったものの、全て一から作成するってことがこれまでなかったわけです。
JQueryすら意識して初めてまともに使うくらいに遠ざかってました。

学んだことをブログの方に反映していきます。

最近、Sign in や Login など調べました。
[ログの語源にまつわる話](https://qiita.com/yaju/items/ae2767c5ebb64da5a096)

# 開発環境
* Visual Studio 2017 Communicate
* ASP.NET(C#) MVC5
* EntityFramework6
* JQuery3.3.1
* Boostrap4
* Chrome、IE11

# ログイン画面
Bootstrap のUIパーツを集めたサイト「[Bootsnipp](https://bootsnipp.com/)」には、ログイン画面のサンプルが幾つか公開されています。
[Bootstrap 4 Login Examples](https://bootsnipp.com/tags/login/4?page=1)

今回は気に入った1つを選択します。
["Login form, sign in form, bootstrap 4 login card, signin page, login style"](https://bootsnipp.com/snippets/j6r4X)

入力する左部分にアイコンがあるとオシャレですよね。
![Signin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/8a4e326b-e3ae-e764-7b62-83a16510d5cc.png)

```html
<html>
<body>
<head>
<title>ログイン</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css">
</head>
<body>
<p>Login form style 3</p>

<div class="card">
<article class="card-body">
	<h4 class="card-title text-center mb-4 mt-1">Sign in</h4>
	<hr>
	<p class="text-success text-center">Some message goes here</p>
	<form>
	<div class="form-group">
	<div class="input-group">
		<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-user"></i> </span>
		 </div>
		<input name="" class="form-control" placeholder="Email or login" type="email">
	</div> <!-- input-group.// -->
	</div> <!-- form-group// -->
	<div class="form-group">
	<div class="input-group">
		<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-lock"></i> </span>
		 </div>
	    <input class="form-control" placeholder="******" type="password">
	</div> <!-- input-group.// -->
	</div> <!-- form-group// -->
	<div class="form-group">
	<button type="submit" class="btn btn-primary btn-block"> Login  </button>
	</div> <!-- form-group// -->
	<p class="text-center"><a href="#" class="btn">Forgot password?</a></p>
	</form>
</article>
</div>
</body>
</html>
```

## カスタム
今回のWEBアプリケーションはユーザーIDとパスワードでログインが出来ればいいので、ASP.NET(C#)で使用する上で簡易的に変更します。
ASP.NET MVC5 EntityFramework6 を使用していますので、View-Controller-Model で分けます。

BODYタグや必要なライブラリーのlinkタグおよび共通スクリプトは共通画面(Views/Shared/_Layout.cshtml)に記述しています。

※IE11で互換表示していると画面が崩れると報告を受けて下記の指定をしました。これをするとInternet Explorerを使用している人でも最新バージョンでサイトを表示するようになります。

```html
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
```

### View
![ログイン3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/dbfcb9cf-a789-acfb-8e0c-fcab012f2580.png)

エラーがあった場合、ログインボタンの下にアラートを表示するようにしています。表示後は数秒で自動的に消えるようにしています。
![LoginAlert2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/d08928a1-7a95-0ada-a566-b84b5e74b620.png)

```html:Views/Login/Index.cshtml
<style type="text/css">
    form i.fa {
        position: absolute;
        top: 10px;
        left: 30px;
        z-index: 9999;
    }

    .form-control {
        position: relative;
        padding-left: 45px !important;
    }
</style>

<div id="content">
    @using (Html.BeginForm("Index", "Login", FormMethod.Post, new { id = "fmLogin" }))
    {
        <div class="py-5">
            <div class="container">
                <div class="col-md-6">
                    <div class="card">
                        <div class="card-body" style="background-color:#d1ecf1">
                            <div class="row">
                                <div class="col-md-12">
                                    <span class="mb-4 text-dark">@ViewBag.MsgInfo</span>
                                </div>
                            </div>
                            <div class="row">
                                <span class="pt-2"></span>
                            </div>
                            <div class="row">
                                <div class="col-md-12">
                                    <div class="form-group">
                                        <i class="fa fa-user"></i>
                                        @Html.TextBoxFor(model => model.ID, new { @class = "form-control custom-input", placeholder = @ViewBag.MsgUserID, autofocus = true })
                                    </div>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-12">
                                    <div class="form-group">
                                        <i class="fa fa-lock"></i>
                                        @Html.PasswordFor(model => model.Password, new { @class = "form-control custom-input", placeholder = @ViewBag.MsgPassword })
                                    </div>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-12">
                                    <button type="submit" class="btn btn-primary">@ViewBag.MsgLogin</button>
                                </div>
                            </div>
                        </div>
                    </div>
                    @if (!string.IsNullOrEmpty(@ViewBag.MsgError))
                    {
                        <div id="alert" class="alert alert-danger mt-2" role="alert"><span class="fa fa-exclamation-circle pr-2"></span>@ViewBag.MsgError</div>
                    }
                </div>
            </div>
        </div>
    }
</div>

<script type="text/javascript">
    // アラート情報表示
    $('#alert').fadeIn(1000).delay(3000).fadeOut(2000);
</script>
```

### Controller
コントローラー部分となります。
メッセージを取得してビュー側に反映させるのと、入力されたユーザーIDとパスワードを受け取ってユーザー認証を行い、エラーなどを返すようにしています。
この中のBizLogicクラスにて、メッセージ情報取得処理やユーザー認証判定処理などを行っています。

```csharp:Controllers/LoginController.cs
public class LoginController : Controller
{
    BizLogic _bizLogic = null;

    public LoginController()
    {
        _bizLogic = new BizLogic();

        // MSG_00100:ログイン
        ViewBag.MsgTitle = _bizLogic.GetMessage("00100");
        // MSG_00101:ユーザーIDとパスワードを入力して下さい
        ViewBag.MsgInfo = _bizLogic.GetMessage("00101");
        // MSG_00102:ユーザーID
        ViewBag.MsgUserID = _bizLogic.GetMessage("00102");
        // MSG_00103:パスワード
        ViewBag.MsgPassword = _bizLogic.GetMessage("00103");
        // MSG_00104:ログイン
        ViewBag.MsgLogin = _bizLogic.GetMessage("00104");
        // エラーは空
        ViewBag.MsgError = "";
    }

    /// <summary>
    /// 通常アクセス時
    /// </summary>
    /// <returns>ViewResultオブジェクト</returns>
    public ActionResult Index()
    {
        return View();
    }

    /// <summary>
    /// POST時
    /// </summary>
    /// <param name="model">POSTデータ</param>
    /// <returns>ViewResultオブジェクト</returns>
    [HttpPost]
    public ActionResult Index(LoginViewModels model)
    {
        if (string.IsNullOrEmpty(model.ID))
        {
            // ユーザーIDが未入力の場合
            ViewBag.MsgError = "ユーザーIDが入力されていません。";
        }
        else
        {
            string userID= model.ID;
            string name = "";
            if (!_bizLogic.GetUserName(ref userID, model.Password, ref name))
            {
                ViewBag.MsgError = "ユーザーID、パスワードを確認してください。";
            }
            else
            {
                // ユーザーIDとユーザー名をセット
                model.ID = userID;
                model.Name = name;

                // ユーザー情報をセット
                Session["LoginModel"] = model;
                // ログイン後の遷移先
                return Redirect("Home/Index");
            }
        }

        return View();
    }
}
```

### Model
View側で入力した情報(POST)を受信するのとユーザー認証後のユーザー名を格納するクラスとなります。

```csharp:Models/LoginViewModels.cs
public class LoginViewModels
{
    /// <summary>
    /// ログインID
    /// </summary>
    public string ID { get; set; }
    /// <summary>
    /// ログインパスワード
    /// </summary>
    public string Password { get; set; }

    /// <summary>
    /// ユーザー名
    /// </summary>
    public string Name { get; set; }
}
```

データベースのアクセス処理クラス(DacLogic.cs)から情報を取得するようにしています。
DacLogic.csまで掲載すると長くなるので省略。
メッセージは多言語化対応として言語を指定できるようにしています。

```csharp:Models/BizLogic.cs
public class BizLogic
{
    // 言語
    public string Lang = "ja";
    // データアクセスクラス
    private DacLogic _dacLogic = null;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public BizLogic()
    {
        // データベース接続準備
        _dacLogic = new DacLogic();
    }

    /// <summary>
    /// メッセージを取得する
    /// </summary>
    /// <param name="no">メッセージコード</param>
    /// <returns>メッセージ</returns>
    public string GetMessage(string no)
    {
        return _dacLogic.GetMessage(no, Lang);
    }

    /// <summary>
    /// ユーザー名を取得する
    /// </summary>
    /// <param name="userID,">ユーザーID</param>
    /// <param name="password">パスワード</param>
    /// <param name="userName">ユーザー名</param>
    /// <returns>true:成功 / false:失敗</returns>
    public bool GetUserName(ref string userID, string password, ref string userName)
    {
        return _dacLogic.GetUserName(ref userID, password, ref userName);
    }
}
```

# 最後に
ネット上のASP.NETでログイン画面のサンプルとかあってもダサいんですよね。オシャレなログイン画面を探してみたんですが、これといったものがなかったので今回作ってみました。

今回は簡易版ってことでパスワードは平文なのでセキュリティー上は良くないです。限られたアクセスで使用する運用なので問題にはなってません。
一般な人にも公開するようなログイン処理なら認証ライブラリ`ASP.NET Identiy`を使用した認証にしていくべきでしょう。