ちょっと自粛につかれてしまって佐渡島へキャンプツーリングに行ってしまい、ASP.NET MVCの学習もお久しぶりになってしまいました。なんだかすっかり忘れてしまったような感覚になっておりますが、理解してませんが何とか先に進めてみたいと思います。
UsersController.csの作成
「Controllers」を右クリックして、「追加」、「コントローラー」、「Entity Frameworkを使用した、ビューがあるMVC5コントローラー」と進み、「追加」しました。
上の画像のように、モデルクラスでは、ドロップダウンメニューから「User(TodoApp.Models)」を選択すると、自動的にコントローラー名が「UsersController」となりました。
先に進むと、Controllers内には、「UsersController.cs」が作成され、Views内には、Usersというフォルダが作成されて、WEB上で追加や削除編集する初期画面が作成されました。
UsersController.csの編集
ユーザー管理画面には、管理者(Administrators)しかアクセスできないように制限をかける為に下記のコードを追加しました。
[Authorize(Roles = "Administrators")]
_LayoutPage1.cshtmlの編集
Administoratorsにてログインした時に、ユーザー管理のリンクボタンを表示させるために編集しました。
if (User.IsInRole("Administrators"))
{
<span>|</span>
@Html.ActionLink("ユーザー管理", "Index", new { Controller = "Users" });
}
この編集ができたら動作確認をしてみました。
しっかりと「ユーザー管理」のリンクボタンがでており、リンク先に行くとユーザー管理画面となりました。
また、管理者以外でログインすると、「ユーザー管理」のリンクボタンが非表示であることも確認しました。
UsersController.csでロールの選択可能にする編集
いちばん下の行から下記を追加しました。
private void SetRoles(ICollection<Role> userRoles)
{
var roles = userRoles.Select(item => item.Id).ToArray();
var list = db.Roles.Select(item => new SelectListItem()
{
Text = item.RoleName,
Value = item.Id.ToString(),
Selected = roles.Contains(item.Id)
}).ToList();
ViewBag.RoleIds = list;
}
そして、新規のCreate()と編集のEdit(int? id)の時に、上記のコードが呼び出されるように下記のように、
this.SetRoles()を追加しました。
// GET: Users/Create
public ActionResult Create()
{
this.SetRoles(new List<Role>());
return View();
}
// GET: Users/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
User user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
this.SetRoles(user.Roles);
return View(user);
}
コードの詳細の解説は自分のスキルでは理解できませんが、新規の場合は、ロールが選択できるようにして、編集の場合は、設定された現時点のロールが表示されるようにしたんじゃないかと考えます。
ModelsのUser.csの編集
下記のようにロールを追加しました。
[NotMapped]
[DisplayName("ロール")]
public List<int> RoleIds { get; set; }
[NotMapped]は、データベースに保持する必要が無い為に入れる。(?)
ViewsのCreate.cshtmlとEdit.cshtmlの編集
<div class="form-group">
@Html.LabelFor(model => model.RoleIds, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.ListBox("RoleIds",null,new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.RoleIds,"", new { @class = "text-danger" })
</div>
</div>
ユーザーとパスワードの欄がWEBページ上にありますが、その下にロールの部分が表示されるように上のコードを挿入しました。
残念ですが、コードの内容で具体的に何をやっているのかは理解できません。
UsersController.csの編集(アクションメソッドの実装)
// GET: Users/Create
public ActionResult Create()
{
this.SetRoles(new List<Role>());
return View();
}
// POST: Users/Create
// 過多ポスティング攻撃を防止するには、バインド先とする特定のプロパティを有効にしてください。
// 詳細については、https://go.microsoft.com/fwlink/?LinkId=317598 をご覧ください。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,UserName,Password,RoleIds")] User user)
{
var roles = db.Roles.Where(role => user.RoleIds.Contains(role.Id)).ToList();
if (ModelState.IsValid)
{
user.Roles = roles;
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
this.SetRoles(roles);
return View(user);
}
// GET: Users/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
User user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
this.SetRoles(user.Roles);
return View(user);
}
// POST: Users/Edit/5
// 過多ポスティング攻撃を防止するには、バインド先とする特定のプロパティを有効にしてください。
// 詳細については、https://go.microsoft.com/fwlink/?LinkId=317598 をご覧ください。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,UserName,Password,RoleIds")] User user)
{
var roles = db.Roles.Where(role => user.RoleIds.Contains(role.Id)).ToList();
if (ModelState.IsValid)
{
var dbUser = db.Users.Find(user.Id);
if (dbUser == null)
{
return HttpNotFound();
}
dbUser.UserName = user.UserName;
dbUser.Password = user.Password;
dbUser.Roles.Clear();
foreach (var role in roles)
{
dbUser.Roles.Add(role);
}
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
this.SetRoles(user.Roles);
return View(user);
}
何やっているのか理解できませんが、こんな感じで実装すればいいんだろうなって感じで進めるしかないですね。
this.SetRoles(user.Roles);
の部分は、エラーが出た時に、入力した画面を復元するためのコードだそうです。
動作確認
管理者でログインした後、ユーザーの追加や編集をすると、ロールと言う部分が出現するようになりました。
これにより簡単にユーザーの権限変更が可能になりました。
何度も言いますが、
ココが残念
自分のスキルではコードの理解ができません
今のところは、丸写しで自分がやりたいと思っている仕組みにユーザー管理機能が実装できれば良しとします。
https://pctips.jp/security/udemy-aspnet-7/