セキュリティ Server

【Udemy学習#5】ASP.NET MVCでEntity Framework?を使ってデータベース管理のログイン機能実装

前回やったログイン機能と今回のログイン機能の違いが全く分かっていませんが、挫折寸前になりながらも耐えていますので頑張りたいと思います。

【Udemy学習#4】ASP.NET MVCでメンバーシッププロバイダーを使ってログイン認証機能を実装

はい!出たー専門用語を調べる

自分の場合は、専門用語が出た段階で挫折寸前に精神状態が追い込まれますが、心を無にして、専門用語を調べることから始めたいと思います。

Entity Frameworkって?

Entity Frameworkはデータベースへのアクセスを容易にするための機能です。
構文がSQLライクとなっており、データの取得や更新、削除などの各種処理を行う際にSQLの文法に近い形で処理を記載することができます。そのため、SQLを理解していれば様々な処理が実装しやすくなります。

Entity Frameworkでは、コードファーストという機能が利用できます。
この機能は、コードでデータベースのテーブルやカラムを定義し、定義からデータベースを自動で作成するという機能です。
ウォーターフォールの開発では、最初にテーブル設計を行い、すべてのテーブルを作成してからコードの実装を始めるというのが多いですが、それとは逆の考え方です。
コードを先に実装して、そこからテーブルを作成することによって、テーブルの変更などにも柔軟に対応でき、実装がしやすくなります。

これにより、手動でデータベースを作成する必要もなく、作成したコードと簡単に連携することができます。この時、データベースへの接続なども自動で行うため、接続文字列の記載は必要ありません。

また、SQLを実行する際にもC#のプログラムとは別にSQLを記述する必要がないため、コードを分かりやすく記述できます。
(引用:.net column

前回は、ログイン情報をコードに埋め込んでいましたが、ユーザー等の情報をデータベース管理するために、Entity Frameworkってのを使えば簡単に実装できると思っていればいいのかな。

まだフワフワしていてよくわかりませんが、とにかく学習動画内容に沿って進むことにしました。

講座の学習内容に沿って作業

ModelsにUser.csを作成

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;

namespace TodoApp.Models
{
    public class User
    {
        public int Id { get; set; }
        [Required]
        [Index(IsUnique = true)]
        [StringLength(256)]
        [DisplayName("ユーザー名")]
        public string UserName { get; set; }
        [Required]
        [DataType(DataType.Password)]
        [DisplayName("パスワード")]
        public string Password { get; set; }

        public virtual ICollection<Role> Roles { get; set; }
    }
}

[Index(IsUnique = true)]
[StringLength(256)]

このコードにより、重複を防ぐ効果があるらしい。

public virtual ICollection<Role> Roles { get; set; }

このコードにより、一人ユーザーが複数のロールを設定できるらしい。

ModelsにRole.csを作成

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace TodoApp.Models
{
    public class Role
    {
        public int Id { get; set; }
        public string RoleName { get; set; }
        public virtual ICollection<User> Users { get; set; }
    }
}

public virtual ICollection<User> Users { get; set; }

上のコードにより、ひとつのロールに対して、複数のユーザーの設定ができるらしい。

ModelsにTodoesContext.csの修正

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace TodoApp.Models
{
    public class TodoesContext :DbContext
    {
        public DbSet<Todo> Todoes { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<Role> Roles { get; set; }
    }
}

未だにコンテキストの意味が分かっていませんが、コードの内容を見ると、データベースにテーブルを作成するような設定じゃないかと推測しています。

CustomMembershipProvider.csの編集

 public override bool ValidateUser(string username, string password)
        {
          using (var db = new TodoesContext())
            {
                var user = db.Users
                    .Where(u => u.UserName == username && u.Password == password)
                    .FirstOrDefault();

                if (user != null)
                {
                    return true;
                }
            }
            return false;
        }

この設定により、データベースから、usernameとpasswordの一致するものを取得しているらしい。

FirstOrDefault()

では、ユーザーが一致しなければ、Nullを返すコードらしい。

あとは、一致すれば、trueとなり、一致しなければ、falseになるというコードですね。

CustomRoleProvider.csの編集(エラー発生)

        public override string[] GetRolesForUser(string username)
        {
            using (var db = new TodoesContext())
            {
                var user = db.Users
                    .Where(u => u.UserName == username)
                    .FirstOrDefault();

                if (user != null)
                {
                    return user.Roles.Select(role => role.RoleName).ToArray();
                }
            }
            return new string[] { };
        }


        public override bool IsUserInRole(string username, string roleName)
        {
            string[] roles = this.GetRolesForUser(username);
            return roles.Contains(roleName);
        }

上記のように2ヶ所を編集しました。

しかし、下記のようにエラーがでて先に進めませんでした。

ココに注意

定義が含まれておらずアセンブリ参照が不足しています

的な注意文がでてくるのですが、全く意味が理解できません。

何かが足りないのかとネットで調べまくりましたが時間だけが過ぎていきました。

コードを見直すと追加した事のない一行が追加されてました。

この一行を消しても波線は消えませんでした。

挫折寸前になりながらも、もう一度、他のコードも見直すと、TodoesContext.csの一部分が書き換わっていました。

Userの部分が、Usersに書き換わっていました。なんで???

波線のエラーを消そうと適当な事をやっているので勝手に書き換わるのでしょうか!?

現在の自分のスキルでは原因がわかりません。

UsersをUserに書き換えたら、RoleNameの波線が消えました。

Entity Frameworkのマイグレーション機能を有効にする

現時点では、データベースにユーザーやロールの情報が登録されてないので、初期データを登録する必要がある。その為に、モデルクラスを元にデータベース(テーブル含む)を作成したり変更したりする仕組みであるマイグレーションを行う。

今回は、ModelsにあるRole.csやTodo.csやUser.csを変更すると自動的にデータベースに内容が反映させるようになるらしい。

(1)ツール>>NuGetパッケージマネージャー>>パッケージマネージャーコンソールを起動

PM> Enable-Migrations -EnableAutomaticMigrations

一文字間違ってもエラーになりますが、間違わずに入力しても何だかエラーがでました。

マイグレーションエラー

202009160411389_InitialCreate.csが見つからないよって言っているようです。

9月16日辺りで何か余計な事をやったのかもしれません・・・

意味が分かっていませんが、とりあえず、ソリューションエクスプローラーを見ると、Migrationsというフォルダもあり、Configuration.csも出来上がっているので先に進みました。

(2)MigrationsのConfiguration.csの編集

オンライン学習の内容の通りにコードをインプットしたのに、赤い波線がきえません。

現在のコンテキストに’users’という名前は存在しません」となります。

結論的には、先頭文字が大文字か小文字かの違いだけでしたが難しい。(´;ω;`)ウゥゥ

namespace TodoApp.Migrations
{
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using TodoApp.Models;

    internal sealed class Configuration : DbMigrationsConfiguration<TodoApp.Models.TodoesContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
            ContextKey = "TodoApp.Models.TodoesContext";
        }

        protected override void Seed(TodoApp.Models.TodoesContext context)
        {
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method
            //  to avoid creating duplicate seed data.
            User admin = new User()
            {
                Id = 1,
                UserName = "admin",
                Password = "Password",
                Roles = new List<Role>()
            };

            User ma2n2n = new User()
            {
                Id = 2,
                UserName = "ma2n2n",
                Password = "password",
                Roles = new List<Role>()
            };

            Role administrators = new Role()
            {
                Id = 1,
                RoleName = "Administrators",
                Users = new List<User>()
            };

            Role users = new Role()
            {
                Id = 2,
                RoleName = "Users",
                Users = new List<User>()
            };

            admin.Roles.Add(administrators);
            administrators.Users.Add(admin);
            ma2n2n.Roles.Add(users);
            users.Users.Add(ma2n2n);

            context.Users.AddOrUpdate(User => User.Id, new User[] { admin, ma2n2n });
            context.Roles.AddOrUpdate(role => role.Id, new Role[] { administrators, users });

        }
    }
}

このコードを見ると、データベースに初期データを登録している事がなんとなくわかりますね。

context.Users.AddOrUpdate(User => User.Id, new User[] { admin, ma2n2n });

この部分は、同じユーザーだったら、更新して、無い場合は追加するという処理らしい。

Global.asaxのGlobal.asax.csの編集

この編集部分は、TodoAppが実行された時に、データベース初期設定のConfiguration.csが実行されるようにする処理コードらしい。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using TodoApp.Migrations;
using TodoApp.Models;

namespace TodoApp
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            Database.SetInitializer(new MigrateDatabaseToLatestVersion<TodoesContext,Configuration>());
        }
    }
}

デフォルトの状態では、

using TodoApp.Migrations;

が入ってないので、Configurationの部分に赤波線がでてましたので、考えられる修正を表示するから選択して追加しました。

動作確認

デバッグの開始をすると、Edgeが起動してログイン画面がでてきました。

admin と password でログインすると無事にログインできました。

 

 

ちなみに、https://localhost:44332/Todoes/Indexにて、ログイン後の画面に直接行こうとすると、ログイン画面に戻されました。

正常に動いています!!

 

個人アカウントのma2n2nとpasswordでも無事にログインすることができて正常に動いていることが確認できました。

データベースの方を確認すると、下記のようになっていました。

 

ASP.NET データベース

 

あれ!?タイプミスで、adminのパスワードの先頭を大文字にしているようです。

でも、ログインは小文字でログインできました。

ココに注意

大文字と小文字の判別はしてない

のでしょうかね。

 

まだ、後にオンライン講座が残っているので、そのうち出てきますかね。

 

 

 

-セキュリティ, Server
-, , , ,

Translate »

© 2020 PCTips