ASP.NET MVC
1. 数据的验证
-
在Models文件夹下,为需要验证的model类中加入
using System.ComponentModel.DataAnnotations; 命名空间的引入 -
添加注解:
-
显示自定义名称
[Display(Name = "标题")] public string Title { get; set; }
-
使用正则表达式验证输入的字符串是否符合格式要求。
[RegularExpression(@"^\w+([-+.]\w+)\*@\w+([-.]\w+)\*\.\w+([-.]\w+)\*$", ErrorMessage = "邮箱不正确")] public string Email { get; set; }
-
Required特性,则此项为必填项。用于不为空校验。默认为不允许为空。允许为空则添加AllowEmptyStrings = true
[Required(ErrorMessage = "密码不能为空")] public string Password { get; set; }
-
限定字符串长度。
[StringLength(20,ErrorMessage = "密码不能超过20个字符")] public string Password { get; set; }
-
用来判断两个属性是否拥有相同的值。例如,确保两次输入的密码相同。比较两个值是否一致,一般用于二次输入。Password是需要比较的值
[Compare("Password",ErrorMessage = "两次输入不一致")] public string PasswordConfirm { get; set; }
以上验证将对PasswordConfirm和Password进行是否一致的比较。
-
Remote利用服务器端的回调函数执行客户端的逻辑验证。这个在登录的时候用的非常多。比如你的用户名ID是否已经被注册
需要添加 using System.Web.Mvc;
[Remote("CheckUserName","Home",ErrorMessage = "用户名已被注册")] public string UserName { get; set; }
然后在Home这个Controller里面添加CheckUserName方法,判断用户名是否存在需要从数据库读取判断,此处只是demo
public ActionResult CheckUserName() { string LastName = Request["LastName"]; if ("admin".Equals(LastName)) return Json(false, JsonRequestBehavior.AllowGet); return Json(true, JsonRequestBehavior.AllowGet); }
-
-
添加视图,在视图页面确保已添加 Jquery库、Jquery.Validate、Jquery.Validate.unobtrusive这三个文件。
小贴士:在创建视图时选择 Create 模板,自带上面这三个,亲测有用哦。
2. Action过滤器
自定义Actioon过滤器
- 首先新建Filters文件夹,在Filters下新建如下图所示
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Demo.Filters
{
public class MyActionFilterAttribute : ActionFilterAttribute
{
public string Message { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
filterContext.HttpContext.Response.Write("Action执行之前" + Message + "<br />");
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.HttpContext.Response.Write("Action执行之后" + Message + "<br />");
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
filterContext.HttpContext.Response.Write("返回Result之前" + Message + "<br />");
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
filterContext.HttpContext.Response.Write("返回Result之后" + Message + "<br />");
}
}
}
-
在需要的控制器下添加方法
[MyActionFilter] //也可以加参数 [MyActionFilter(Message="lwjppz")] public ActionResult ActionFilterDemo() { return View(); }
添加视图后,运行结果:
3. Authorization过滤器
在MVC中使用AuthorizeAttribute实现登陆和权限控制。
在执行需要登录和权限的Action前先判断用户是否登陆,若没登陆就跳转到登陆页,然后再判断用户是否有权限访问该Action对应的视图页面,若没有则跳转到特定提示页。
范例:
先添加一个控制器AccountController:
public class AccountController : Controller
{
public ActionResult Index()
{
return View();
}
}
然后再web.config文件中的<system.web>节中添加:
<authentication mode="Forms">
<forms loginUrl="~/Account/Index" timeout="2880" />
</authentication>
用来启用登录和权限验证,当用户未登录时将跳转到loginUrl指定的页面。
Forms 身份验证将身份验证标记保留在 Cookie 或页的 URL 中。Forms 身份验证通过 FormsAuthenticationModule 类参与到 ASP.NET 页面的生命周期中。可以通过 FormsAuthentication 类访问 Forms 身份验证信息和功能。
然后,在filterConfig.cs文件中的RegisterGlobalFilters方法中添加:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AuthorizeAttribute());
}
运行程序,当访问Home控制器下的Index页面时会跳转到Account控制器的Index页面,显示如下页面:
某一些页面是需要未登录也能访问的,此时我们可以在相应的Action上添加匿名登录标记[AllowAnonymous],例如上面的Home控制器中的Index页面和Account控制器中的Index页面都需要匿名访问权限:
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
此时再访问Home控制器中的Index页面就能正常显示了。
需要注意的是,如果在能够匿名访问的页面中嵌套了需要登录和权限的子页面,则匿名访问的页面不能正常显示。例如:
在Home控制器中的Index视图页面中嵌套了@{Html.RenderAction("ChildActionOnly");}语句,即内嵌了ChildActionOnly页面,而该页面是需要登录才能访问的,则Index页面也不能正常显示。
此时再运行程序,访问需要登录的页面时会跳转到登录页面:
注意,如果Account控制器的Index登录页面没有匿名访问标记则会提示错误:
登录系统
登录的控制器中在用户名和密码验证成功之后,应添加代码
FormsAuthentication.SetAuthCookie(username, false);
可用User.Identity.Name来获取当前的登录名,如:
string userid = HttpContext.User.Identity.Name;
范例:
修改Account控制器中的Index方法:
[AllowAnonymous]
public ActionResult Index()
{
string returnURL = Request["ReturnUrl"];
ViewBag.returnURL = returnURL;
return View();
}
在Account控制器中添加一个Action,用于校验用户输入的用户名和密码是否正确:
[AllowAnonymous]
public ActionResult Login(string username,string password,string returnURL)
{
if ("admin".Equals(username) && "123456".Equals(password))
{
FormsAuthentication.SetAuthCookie(username, false);//设置用户登录成功(设置cookie),false表示cookie不要持久保存**
if (Url.IsLocalUrl(returnURL))
{
return Redirect(returnURL);
}
return RedirectToAction("Index","Home");
}
return View();
}
此时再访问需要登录才能访问的页面会跳转到登录页面,在登录页面输入正确的用户名和密码后就可以访问所有需要登录才能访问的页面了。
退出登录
使用如下的语句来退出登录:
FormsAuthentication.SignOut();//通过Forms验证来删除Cookie
权限的验证
可以指定某个Controller或某个Action只能由指定的用户或角色访问。
指定特定用户访问
可以使用[Authorize(Users="登录的用户名")]的方式来限定。
如果可以由多个用户访问,在不同用户间用逗号分隔。
范例:
在Home控制器中修改Action:
在一个Action前面加上:
[Authorize(Users="admin")]
表示该Action只能由用户admin访问。
在另一个Action前面加上:
[Authorize(Users="sysadmin")]
表示该Action只能由用户sysadmin访问。
指定特定角色访问
可以使用[Authorize(Roles="登录的用户名所属的角色")]的方式来限定。
如果可以由多个角色访问,在不同角色间用逗号分隔。
范例:
在Home控制器中修改Action:
在一个Action前面加上:
[Authorize(Roles="admin")]
表示该Action只能由角色admin访问。
在另一个Action前面加上:
[Authorize(Roles="sysadmin")]
表示该Action只能由角色sysadmin访问。
需要注意的是:
1、我们必须实现自己的RoleProvider,主要是从RoleProvider这个抽象类派生出自己的子类,并重写其中的GetRolesForUser方法:
public class CustomRoleProvider:RoleProvider
{
public override string[] GetRolesForUser(string username)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var ticket = FormsAuthentication.Decrypt(cookie.Value);
string role = ticket.UserData;
return role.Split(',');
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override string ApplicationName
{
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
throw new NotImplementedException();
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
2、必须修改web.config文件中的设置:
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear/>
<add name="CustomRoleProvider" type="FilterDemo.Filters.CustomRoleProvider"/>
</providers>
</roleManager>
注意:这里type必须改成自己的命名空间.文件夹.类名。name的值可以与类名不同。但必须保证defaultProvider的值必须是下面add中某个name的值。
3、在登录验证的Action中自己定义cookie来存放用户名和角色信息:
[AllowAnonymous]
public ActionResult Logon(string username, string password, string returnUrl)
{
if ("admin".Equals(username) && "123456".Equals(password))
{
string role = "admin,sysadmin";
var authTicket = new FormsAuthenticationTicket(
1, // 版本
username, // 用户名称
DateTime.Now, // 创建日期
DateTime.Now.AddMinutes(20), // 过期时间
false, // 是否记住
role // 用户角色
);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.HttpOnly = true;//客户端脚本不能访问
authCookie.Secure = FormsAuthentication.RequireSSL;//是否仅用https传递cookie
authCookie.Domain = FormsAuthentication.CookieDomain;//与cookie关联的域
authCookie.Path = FormsAuthentication.FormsCookiePath;//cookie关联的虚拟路径
Response.Cookies.Add(authCookie);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Account");
}
return RedirectToAction("Index", "Account");
}
Q.E.D.