ASP.NET MVC使用Identity增删改查用户

源码在这里:https://github.com/darrenji/UseIdentityCRUDUserInMVC本地下载

在VS2013中创建一个MVC项目,用默认的”无身份验证”作为身份验证机制。

通过控制台下载Bootstrap。

Install-Package -version 3.0.3 bootstrap

下载成功后,在解决方案下的Content和Scripts多了该版本的css和js文件。

把创建项目默认HomeController中的所有Action以及/Views/Home下的所有视图删除。

热热身

先来做一个简单练习。

在HomeController中的Index方法中,把一个字典传递给视图。

1
2
3
4
5
6
7
8
9
public class HomeController : Controller
{
    public ActionResult Index()
    {
        Dictionary<string object=""> data = new Dictionary<string object="">();
        data.Add("placeholder", "placeholder");
        return View(data);
    }
}</string></string>

_Layout.cshtml设置如下:

1
2
3
4
5
6
7
8
9
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ASP.NET Identity实战</title><link href="~/Content/bootstrap.min.css" rel="external nofollow"><link href="~/Content/bootstrap-theme.min.css" rel="external nofollow"><style>
        .container {padding-top:10px;}
        .validation-summary-errors{color:red;}
    </style><div class="container">
        @RenderBody()
    </div>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)

Home/Index.cshtml视图中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="panel panel-primary">
    <div class="panel-heading">用户明细</div>
     
        @foreach (string key in Model.Keys)
        {
             
        }
    <table class="table table-striped"><tbody><tr>
<th>@key</th>
                <td>@Model[key]</td>
            </tr></tbody></table>
</div>

前期准备

分别安装如下组件。

Install-Package Microsoft.AspNet.Identity.EntityFramework –Version 2.0.0
Install-Package Microsoft.AspNet.Identity.OWIN -Version 2.0.0
Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.0

配置Web.config如下:

1
<!--?xml version="1.0" encoding="utf-8"?--><configuration><configsections><section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirepermission="false"></section></configsections><connectionstrings><add name="IdentityDb" providername="System.Data.SqlClient" connectionstring="Data Source=(localdb)v11.0;Initial Catalog=IdentityDb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;MultipleActiveResultSets=True"></add></connectionstrings><appsettings><add key="webpages:Version" value="3.0.0.0"></add><add key="webpages:Enabled" value="false"></add><add key="ClientValidationEnabled" value="true"></add><add key="UnobtrusiveJavaScriptEnabled" value="true"></add><add key="owin:AppStartup" value="WebApplication4.IdentityConfig"></add></appsettings><system.web><compilation debug="true" targetframework="4.5"></compilation><httpruntime targetframework="4.5"></httpruntime></system.web><runtime><assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentassembly><assemblyidentity name="System.Web.Helpers" publickeytoken="31bf3856ad364e35"></assemblyidentity><bindingredirect oldversion="1.0.0.0-3.0.0.0" newversion="3.0.0.0"></bindingredirect></dependentassembly><dependentassembly><assemblyidentity name="System.Web.Mvc" publickeytoken="31bf3856ad364e35"></assemblyidentity><bindingredirect oldversion="1.0.0.0-5.0.0.0" newversion="5.0.0.0"></bindingredirect></dependentassembly><dependentassembly><assemblyidentity name="System.Web.Optimization" publickeytoken="31bf3856ad364e35"></assemblyidentity><bindingredirect oldversion="1.0.0.0-1.1.0.0" newversion="1.1.0.0"></bindingredirect></dependentassembly><dependentassembly><assemblyidentity name="System.Web.WebPages" publickeytoken="31bf3856ad364e35"></assemblyidentity><bindingredirect oldversion="1.0.0.0-3.0.0.0" newversion="3.0.0.0"></bindingredirect></dependentassembly><dependentassembly><assemblyidentity name="WebGrease" publickeytoken="31bf3856ad364e35"></assemblyidentity><bindingredirect oldversion="0.0.0.0-1.5.2.14234" newversion="1.5.2.14234"></bindingredirect></dependentassembly></assemblybinding></runtime><entityframework><defaultconnectionfactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"></defaultconnectionfactory><providers><provider invariantname="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"></provider></providers></entityframework></configuration>

以上,

  • 增加了connectionStrings节点,将自动创建localdb数据库
  • 在appSettings节点中增加了一个key为owin:AppStartup项,这是确保OWIN运行正常的全局配置

在Models文件夹下创建如下类。

1
2
3
public class AppUser : IdentityUser
{
}

在解决方案下创建Infrastructure文件夹。

在Infrastructure文件夹下创建一个上下文类,需要实现IdentityDbContext接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class AppIdentityDbContext : IdentityDbContext<appuser>
 {
     public AppIdentityDbContext()
         : base("IdentityDb")
     {
     }
     static AppIdentityDbContext()
     {
         //使用EF Code First第一次创建的时候调用
         Database.SetInitializer<appidentitydbcontext>(new IdentityDbInit());
     }
     public static AppIdentityDbContext Create()
     {
         return new AppIdentityDbContext();
     }
 }
 //初始化
 public class IdentityDbInit : DropCreateDatabaseIfModelChanges<appidentitydbcontext>
 {
     protected override void Seed(AppIdentityDbContext context)
     {
         PerformInitialSetup(context);
         base.Seed(context);
     }
     //初始化工作
     public void PerformInitialSetup(AppIdentityDbContext context)
     { }
 }</appidentitydbcontext></appidentitydbcontext></appuser>

在Infrastructure文件夹下创建一个管理用户的类,需要继承UserManager类。

还记得,先前在appSettings节点中配置了一个如下方式:

OWIN需要一个全局启动文件,默认会到项目的顶级命名空间下找IdentityConfig这个类。

那就在App_Start中创建IdentityConfig这个类,这个类在WebApplication4这个命名空间下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace WebApplication4
{
    public class IdentityConfig
    {
        public void Configuration(IAppBuilder app)
        {
            app.CreatePerOwinContext<appidentitydbcontext>(AppIdentityDbContext.Create);
            app.CreatePerOwinContext<appusermanager>(AppUserManager.Create);
            app.UseCookieAuthentication(new CookieAuthenticationOptions {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new Microsoft.Owin.PathString("/Account/Login")
            });
        }
    }
}</appusermanager></appidentitydbcontext>

显示用户

创建AdminController,现在可以向视图传递所有的用户了,编写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AdminController : Controller
{
    public ActionResult Index()
    {
        return View(UserManager.Users);
    }
    private AppUserManager UserManager
    {
        get
        {
            return HttpContext.GetOwinContext().GetUserManager<appusermanager>();
        }
    }
}</appusermanager>

再创建Admin/Index.cshtml类型为IEnumerable的强类型视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@model IEnumerable<webapplication4.models.appuser>
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="panel panel-primary">
    <div class="panel-heading">
        所有用户账户
    </div>
     
        @if (Model.Count() == 0)
        {
             
        }
        else
        {
            foreach (WebApplication4.Models.AppUser user in Model)
            {
                 
            }
        }
    <table class="table table-striped">
<tbody><tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th></th>
</tr><tr><td colspan="4" class="text-center">还没有创建用户</td></tr><tr>
<td>@user.Id</td>
                    <td>@user.UserName</td>
                    <td>@user.Email</td>
                    <td>
                        @using (Html.BeginForm("Delete", "Admin",
                            new { id = user.Id }))
                        {
                            @Html.ActionLink("编辑", "Edit", new { id = user.Id },
                                    new { @class = "btn btn-primary btn-xs" })
                            <button class="btn btn-danger btn-xs" type="submit">
                                删除
                            </button>
                        }
                    </td>
                </tr></tbody></table>
</div>
@Html.ActionLink("创建用户", "Create", null, new { @class = "btn btn-primary" })</webapplication4.models.appuser>

创建用户

在Models文件夹下创建一个视图模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace WebApplication4.Models
{
    public class CreateModel
    {
        public string Id { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Email { get; set; }
        [Required]
        public string Password { get; set; }
    }
}

在AdminController中添加创建用户相关的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class AdminController : Controller
 {
     public ActionResult Index()
     {
         return View(UserManager.Users);
     }
     //创建显示
     public ActionResult Create()
     {
         return View();
     }
     [HttpPost]
     public async Task<actionresult> Create(CreateModel model)
     {
         if(ModelState.IsValid)
         {
             var user = new AppUser{UserName = model.Name, Email = model.Email};
             IdentityResult result = await UserManager.CreateAsync(user, model.Password);
             if(result.Succeeded)
             {
                 return RedirectToAction("Index");
             }else{
                 AddErrorsFromResult(result);
             }
         }
         return View(model);
     }
     //创建接收
     private void AddErrorsFromResult(IdentityResult result)
     {
         foreach(var error in result.Errors)
         {
             ModelState.AddModelError("", error);
         }
     }
     private AppUserManager UserManager
     {
         get
         {
             return HttpContext.GetOwinContext().GetUserManager<appusermanager>();
         }
     }
 }</appusermanager></actionresult>

在Admin/Create.cshtml视图页中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@model WebApplication4.Models.CreateModel
@{
    ViewBag.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
     
    <div class="form-horizontal">
        <h4>创建用户</h4>
        <hr>
        @Html.ValidationSummary(true)
        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email)
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password)
                @Html.ValidationMessageFor(model => model.Password)
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="创建用户" class="btn btn-default">
</div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("返回", "Index")
</div>

点击”创建”按钮,创建成功返回显示用户页面。

oh, my god,只是配置了一下就有数据了? 数据在哪呢?

点击左上角的”服务器资源管理器”,右键”IdentityDb”,点击”刷新”。

再打开AspNetUsers表,刚创建的用户赫然在列。

好像还有点欠缺,用户输入密码的时候,总应该有些限制吧。

能想到的,ASP.NET Identity都为我们准备好了。有一个PasswordValidator类就是干这个的。

在Infrastructure文件夹中创建一个PasswordValidator类的继承子类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace WebApplication4.Infrastructure
{
    public class CustomPasswordValidator : PasswordValidator
    {
        public override async Task<identityresult> ValidateAsync(string pass)
        {
            IdentityResult result = await base.ValidateAsync(pass);
            if (pass.Contains("12345"))
            {
                var errors = result.Errors.ToList();
                errors.Add("密码中包含太多连续数字");
                result = new IdentityResult(errors);
            }
            return result;
        }
    }
}</identityresult>

然后需要把这个规则告诉UserManager。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace WebApplication4.Infrastructure
{
    public class AppUserManager : UserManager<appuser>
    {
        public AppUserManager(IUserStore<appuser> store) : base(store) { }
        public static AppUserManager Create(IdentityFactoryOptions<appusermanager> options, IOwinContext context)
        {
            //identity ef上下文
            AppIdentityDbContext db = context.Get<appidentitydbcontext>();
            //与identity ef相关的UserStore
            IUserStore<appuser> us = new UserStore<appuser>(db);
            AppUserManager manager = new AppUserManager(us);
            //密码相关
            manager.PasswordValidator = new CustomPasswordValidator {
                RequiredLength = 6,
                RequireNonLetterOrDigit = false,
                RequireDigit = false,
                RequireLowercase = true,
                RequireUppercase = true
            };
            return manager;
        }
    }
}</appuser></appuser></appidentitydbcontext></appusermanager></appuser></appuser>

再次运行程序,创建用户页面,尝试输入不通过的密码。

不过,关于密码的规则,似乎可以在View Model的验证层面就可以解决掉。

编辑和删除用户

在AdminController中增加编辑和删除的部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
public class AdminController : Controller
{
    public ActionResult Index()
    {
        return View(UserManager.Users);
    }
    //创建显示
    public ActionResult Create()
    {
        return View();
    }
    //创建接收
    [HttpPost]
    public async Task<actionresult> Create(CreateModel model)
    {
        if(ModelState.IsValid)
        {
            var user = new AppUser{UserName = model.Name, Email = model.Email};
            IdentityResult result = await UserManager.CreateAsync(user, model.Password);
            if(result.Succeeded)
            {
                return RedirectToAction("Index");
            }else{
                AddErrorsFromResult(result);
            }
        }
        return View(model);
    }
    //编辑显示
    public async Task<actionresult> Edit(string id)
    {
        AppUser user = await UserManager.FindByIdAsync(id);
         
        if(User != null)
        {
            CreateModel createModel = new CreateModel();
            createModel.Id = user.Id;
            createModel.Email = user.Email;
            createModel.Name = user.UserName;
            createModel.Password = user.PasswordHash;
            return View(createModel);
        }
        else
        {
            return RedirectToAction("Index");
        }
    }
    //接收编辑
    [HttpPost]
    public async Task<actionresult> Edit(CreateModel createModel)
    {
         
        if(ModelState.IsValid)
        {
            AppUser user = await UserManager.FindByIdAsync(createModel.Id);
            if (user != null)
            {
                //关于邮箱
                user.Email = createModel.Email;
                IdentityResult validEmail = await UserManager.UserValidator.ValidateAsync(user);
                if (!validEmail.Succeeded)
                {
                    AddErrorsFromResult(validEmail);
                }
                user.UserName = createModel.Name;
                //关于密码
                IdentityResult validPass = null;
                if (createModel.Password != string.Empty)
                {
                    validPass = await UserManager.PasswordValidator.ValidateAsync(createModel.Password);
                    if (validPass.Succeeded)
                    {
                        user.PasswordHash = UserManager.PasswordHasher.HashPassword(createModel.Password);
                    }
                    else
                    {
                        AddErrorsFromResult(validPass);
                    }
                }
                user.Email = createModel.Email;
                //验证结果
                if ((validEmail.Succeeded && validPass == null) || (validEmail.Succeeded
&& createModel.Password != string.Empty && validPass.Succeeded))
                {
                    IdentityResult result = await UserManager.UpdateAsync(user);
                    if (result.Succeeded)
                    {
                        return RedirectToAction("Index");
                    }
                    else
                    {
                        AddErrorsFromResult(result);
                    }
                }
                else
                {
                    ModelState.AddModelError("", "无此用户");
                }
            }
            return View(createModel);
        }
        else
        {
            return View(createModel);
        }
         
    }
    //删除
    [HttpPost]
    public async Task<actionresult> Delete(string id)
    {
        AppUser user = await UserManager.FindByIdAsync(id);
        if(user != null)
        {
            IdentityResult result = await UserManager.DeleteAsync(user);
            if(result.Succeeded)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return View("Error", result.Errors);
            }
        }
        else
        {
            return View("Error", new string[] { "没有此用户" });
        }
    }
    private void AddErrorsFromResult(IdentityResult result)
    {
        foreach(var error in result.Errors)
        {
            ModelState.AddModelError("", error);
        }
    }
    private AppUserManager UserManager
    {
        get
        {
            return HttpContext.GetOwinContext().GetUserManager<appusermanager>();
        }
    }
}</appusermanager></actionresult></actionresult></actionresult></actionresult>

Admin/Edit.cshtml视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@model WebApplication4.Models.CreateModel
@{
    ViewBag.Title = "Edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
     
    <div class="form-horizontal">
        <hr>
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)
        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email)
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password)
                @Html.ValidationMessageFor(model => model.Password)
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="保存" class="btn btn-default">
</div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("返回", "Index")
</div>

另外,如果删除失败,跳转到Shared/Error.cshtml视图页。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@model IEnumerable<string>
@{ ViewBag.Title = "Error";}
<div class="alert alert-danger">
    @switch (Model.Count())
    {
        case 0:
            @: Something went wrong. Please try again
            break;
        case 1:
        @Model.First();
                          break;
        default:
        @: 发现如下错误:
        <ul>
            @foreach (string error in Model)
            {
                <li>@error</li>
            }
        </ul>
            break;
    }
</div>
@Html.ActionLink("确定", "Index", null, new { @class = "btn btn-default" })</string>

至此,使用ASP.NET Identy实现对用户的增删改查完毕,ASP.NET Identity真的很好很强大!

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对IT俱乐部的支持。如果你想了解更多相关内容请查看下面相关链接

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/asp-net/1284.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部