一、默认Web项目的更改
用户这部分还是自己做,所以删除自动生成的用户相关代码。
二、添加Member区域
在web项目上点右键 添加 区域Member。
添加Home控制器,选择MVC5控制器-空
我们给public ActionResult Index()添加一个视图,代码很简单就是显示下用户名
1
2
3
4
5
6
|
@{ ViewBag.Title = "会员中心"; } < h2 >欢迎你!@User.Identity.Name </ h2 > |
我们先运行一下,出错啦。
这是因为项目中有两个名为Home的控制器,必须在路由中加上命名空间。先打开区域中的MemberAreaRegistration添加命名空间。
再打开项目中的RouteConfig,添加命名空间
再刷新浏览器,可以正常显示。
再添加用户控制器UserController。
三、模型类的更改
在这里先对Models项目User模型进行修改,原来考虑的是每个用户只能属于一个用户组,后来仔细考虑了一下,还是不太合适,比如一个用户兼任多个角色,所以还是把用户和用户组改成一对多的关系。
- User模型。在模型中删除GroupID,删除外键Group。
- Role模型。原来UserGroup(用户组)改为角色,考虑到权限管理感觉叫角色比叫户组更加合适,另外角色的含义更广,可以是指用户组,也可以指职位,还可以指部门……修改后代码如下:
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
|
using System.ComponentModel.DataAnnotations; namespace Ninesky.Models { /// < summary > /// 角色 /// < remarks > /// 创建:2014.02.02 /// 修改:2014.02.16 /// </ remarks > /// </ summary > public class Role { [Key] public int RoleID { get; set; } /// < summary > /// 名称 /// </ summary > [Required(ErrorMessage="必填")] [StringLength(20, MinimumLength = 2, ErrorMessage = "{1}到{0}个字")] [Display(Name="名称")] public string Name { get; set; } /// < summary > /// 角色类型< br /> /// 0普通(普通注册用户),1特权(像VIP之类的类型),3管理(管理权限的类型) /// </ summary > [Required(ErrorMessage = "必填")] [Display(Name = "用户组类型")] public int Type { get; set; } /// < summary > /// 说明 /// </ summary > [Required(ErrorMessage = "必填")] [StringLength(50, ErrorMessage = "少于{0}个字")] [Display(Name = "说明")] public string Description { get; set; } /// < summary > /// 获取角色类型名称 /// </ summary > /// < returns ></ returns > public string TypeToString() { switch (Type) { case 0: return "普通"; case 1: return "特权"; case 2: return "管理"; default: return "未知"; } } } } |
UserRoleRelation类。在Models项目添加角色关系类UserRoleRelation类,代码:
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
|
using System.ComponentModel.DataAnnotations; namespace Ninesky.Models { /// < summary > /// 用户角色关系 /// < remarks > /// 创建:2014.02.16 /// </ remarks > /// </ summary > public class UserRoleRelation { [Key] public int RelationID { get; set; } /// < summary > /// 用户ID /// </ summary > [Required()] public int UserID { get; set; } /// < summary > /// 角色ID /// </ summary > [Required()] public int RoelID { get; set; } } } |
NineskyDbContext类。 如下图蓝色框为修改部分,红框为新增加
三、验证码及Sha256加密
1、验证码
现在验证码是网站的必须功能,我把验证码功能分成三块:创建验证码字符、根据验证码生成图片、User控制器action中保存验证码并返回图片。
创建验证码字符 CreateVerificationText()
在Common中添加Security类,在类中利用伪随机数生成器生成验证码字符串。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/// < summary > /// 创建验证码字符 /// </ summary > /// < param name = "length" >字符长度</ param > /// < returns >验证码字符</ returns > public static string CreateVerificationText(int length) { char[] _verification = new char[length]; char[] _dictionary = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; Random _random = new Random(); for (int i = 0; i < length; i++) { _verification[i] = _dictionary[_random.Next(_dictionary.Length - 1)]; } return new string(_verification); } |
根据验证码生成图片CreateVerificationImage()
思路是使用GDI+创建画布,使用伪随机数生成器生成渐变画刷,然后创建渐变文字。
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
|
/// < summary > /// 创建验证码图片 /// </ summary > /// < param name = "verificationText" >验证码字符串</ param > /// < param name = "width" >图片宽度</ param > /// < param name = "height" >图片长度</ param > /// < returns >图片</ returns > public static Bitmap CreateVerificationImage(string verificationText, int width, int height) { Pen _pen= new Pen(Color.Black); Font _font = new Font("Arial", 14, FontStyle.Bold); Brush _brush = null; Bitmap _bitmap = new Bitmap(width,height); Graphics _g = Graphics.FromImage(_bitmap); SizeF _totalSizeF = _g.MeasureString(verificationText,_font); SizeF _curCharSizeF; PointF _startPointF = new PointF((width-_totalSizeF.Width)/2,(height-_totalSizeF.Height)/2); //随机数产生器 Random _random =new Random(); _g.Clear(Color.White); for(int i=0;i<verificationText.Length;i++) { _brush = new LinearGradientBrush(new Point(0,0),new Point(1,1),Color.FromArgb(_random.Next(255),_random.Next(255),_random.Next(255)),Color.FromArgb(_random.Next(255),_random.Next(255),_random.Next(255))); _g.DrawString(verificationText[i].ToString(),_font,_brush,_startPointF); _curCharSizeF = _g.MeasureString(verificationText[i].ToString(),_font); _startPointF.X+= _curCharSizeF.Width; } _g.Dispose(); return _bitmap; } |
User控制器action中保存验证码并返回图片
首先添加User控制器,在Member区域中添加控制器UserController。在控制器中写一个VerificationCode方法。过程是:在方法中我们先创建6位验证码字符串->使用CreateVerificationImage创建验证码图片->把图片写入OutputStream中->把验证码字符串写入TempData中。
保存在TempData中和Session中的区别:TempData只传递一次,也就是传递到下一个action后,action代码执行完毕就会销毁,Session会持续保存,所以验证码用TempData比较合适。
1
2
3
4
5
6
7
8
9
10
11
12
|
/// < summary > /// 验证码 /// </ summary > /// < returns ></ returns > public ActionResult VerificationCode() { string verificationCode = Security.CreateVerificationText(6); Bitmap _img = Security.CreateVerificationImage(verificationCode, 160, 30); _img.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg); TempData["VerificationCode"] = verificationCode.ToUpper(); return null; } |
我们看看生成图验证码效果:
2、Sha256加密
在COmmon项目的Security类中添加静态方法Sha256(string plainText)
1
2
3
4
5
6
7
8
9
10
11
|
/// < summary > /// 256位散列加密 /// </ summary > /// < param name = "plainText" >明文</ param > /// < returns >密文</ returns > public static string Sha256(string plainText) { SHA256Managed _sha256 = new SHA256Managed(); byte[] _cipherText = _sha256.ComputeHash(Encoding.Default.GetBytes(plainText)); return Convert.ToBase64String(_cipherText); } |
四、注册
在Ninesky.Web.Areas.Member.Models中添加注册视图模型
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
|
using System.ComponentModel.DataAnnotations; namespace Ninesky.Web.Areas.Member.Models { public class RegisterViewModel { /// < summary > /// 用户名 /// </ summary > [Required(ErrorMessage = "必填")] [StringLength(20, MinimumLength = 4, ErrorMessage = "{2}到{1}个字符")] [Display(Name = "用户名")] public string UserName { get; set; } /// < summary > /// 显示名 /// </ summary > [Required(ErrorMessage = "必填")] [StringLength(20, MinimumLength = 2, ErrorMessage = "{2}到{1}个字符")] [Display(Name = "显示名")] public string DisplayName { get; set; } /// < summary > /// 密码 /// </ summary > [Required(ErrorMessage = "必填")] [Display(Name = "密码")] [StringLength(20,MinimumLength=6,ErrorMessage="{2}到{1}个字符")] [DataType(DataType.Password)] public string Password { get; set; } /// < summary > /// 确认密码 /// </ summary > [Required(ErrorMessage = "必填")] [Compare("Password", ErrorMessage = "两次输入的密码不一致")] [Display(Name = "确认密码")] [DataType(DataType.Password)] public string ConfirmPassword { get; set; } /// < summary > /// 邮箱 /// </ summary > [Required(ErrorMessage = "必填")] [Display(Name = "邮箱")] [DataType(DataType.EmailAddress,ErrorMessage="Email格式不正确")] public string Email { get; set; } /// < summary > /// 验证码 /// </ summary > [Required(ErrorMessage = "必填")] [StringLength(6, MinimumLength = 6, ErrorMessage = "验证码不正确")] [Display(Name = "验证码")] public string VerificationCode { get; set; } } } |
在UserController中添加Register() action ,并返回直接返回强类型(RegisterViewModel)视图
1
2
3
4
5
6
7
8
|
/// < summary > /// 注册 /// </ summary > /// < returns ></ returns > public ActionResult Register() { return View(); } |
视图
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
|
@model Ninesky.Web.Areas.Member.Models.RegisterViewModel @{ ViewBag.Title = "注册"; Layout = "~/Views/Shared/_Layout.cshtml"; } @using (Html.BeginForm()) { @Html.AntiForgeryToken() < div class = "form-horizontal" > < h4 >用户注册</ h4 > < hr /> @Html.ValidationSummary(true) < div class = "form-group" > @Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.UserName) @Html.ValidationMessageFor(model => model.UserName) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.DisplayName, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.DisplayName) @Html.ValidationMessageFor(model => model.DisplayName) </ 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" > @Html.LabelFor(model => model.ConfirmPassword, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.ConfirmPassword) @Html.ValidationMessageFor(model => model.ConfirmPassword) </ 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.VerificationCode, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.VerificationCode) < img id = "verificationcode" title = "点击刷新" src = "@Url.Action(" VerificationCode")" style = "cursor:pointer" /> @Html.ValidationMessageFor(model => model.VerificationCode) </ div > </ div > < div class = "checkbox" > < input type = "checkbox" checked = "checked" required />我同意 < a href = "#" >《用户注册协议》</ a > </ 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 > } < script type = "text/javascript" > $("#verificationcode").click(function () { $("#verificationcode").attr("src", "@Url.Action("VerificationCode")?" + new Date()); }) </ script > @section Scripts { @Scripts.Render("~/bundles/jqueryval") } |
再在用户控制器中添加public ActionResult Register(RegisterViewModel register)用来处理用户提交的注册数据
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
|
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Register(RegisterViewModel register) { if (TempData["VerificationCode"] == null || TempData["VerificationCode"].ToString() != register.VerificationCode.ToUpper()) { ModelState.AddModelError("VerificationCode", "验证码不正确"); return View(register); } if(ModelState.IsValid) { if (userService.Exist(register.UserName)) ModelState.AddModelError("UserName", "用户名已存在"); else { User _user = new User() { UserName = register.UserName, //默认用户组代码写这里 DisplayName = register.DisplayName, Password = Security.Sha256(register.Password), //邮箱验证与邮箱唯一性问题 Email = register.Email, //用户状态问题 Status = 0, RegistrationTime = System.DateTime.Now }; _user = userService.Add(_user); if (_user.UserID > 0) { return Content("注册成功!"); //AuthenticationManager.SignIn(); } else { ModelState.AddModelError("", "注册失败!"); } } } return View(register); } |
代码中很多根用户设置相关的内容先不考虑,等做到用户设置时在会后来修改。注册失败时返回视图并显示错误;成功时返回视图注册成功,等下次做用户登录时可以让用户注册完毕直接进行登录。看看效果。
点击注册,注册成功。
一个简单的用户注册完成了,主要有验证码、sha256加密、注册视图模型、验证用户提交数据并保存等步骤。后面就是用户注册,注册会用到ClaimsIdentity和HttpContext.GetOwinContext().Authentication.SignIn();
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。