MVC 自定义AuthorizeAttribute实现权限管理
在上一节中提到可以使用AuthorizeAttribute进行权限管理:
[Authorize] public ActionResult TestAuthorize() { return View(); } [Authorize(Users="test1,test2")] public ActionResult TestAuthorize() { return View(); } [Authorize(Roles="Admin")] public ActionResult TestAuthorize() { return View(); }
但是通常情况下,网站的权限并不是固定不变的,当新增角色或者角色改变时,只能修改每个Action对应的特性,当项目较大时工作量可想而知。幸运的是我们可以重写AuthorizeAttribute达到自定义的权限管理。新建一个CustomAuthorizeAttribute类,使这个类继承于AuthorizeAttribute。打开AuthorizeAttribute查看下方法说明,我们只需要重写AuthorizeCore和OnAuthorization就能达到我们的目的。
代码顺序为:OnAuthorization-->AuthorizeCore-->HandleUnauthorizedRequest
如果AuthorizeCore返回false时,才会走HandleUnauthorizedRequest 方法,并且Request.StausCode会返回401,401错误又对应了Web.config中
的
<authentication mode="Forms">
<forms loginUrl="~/" timeout="2880" />
</authentication>
所有,AuthorizeCore==false 时,会跳转到 web.config 中定义的 loginUrl="~/"
public class CheckLoginAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext) {
bool Pass = false;
if (!CheckLogin.AdminLoginCheck())
{
httpContext.Response.StatusCode = 401;//无权限状态码
Pass = false;
}
else
{
Pass = true;
}
return Pass;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if(filterContext.HttpContext.Request.IsAjaxRequest())
{
if (!App.AppService.IsLogon)
{
filterContext.Result = new JsonResult
{
Data = new {IsSuccess = false, Message = "不好意思,登录超时,请重新登录再操作!"},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
return;
}
}
if (App.AppService.IsLogon)
{
return;
}
base.HandleUnauthorizedRequest(filterContext);
if (filterContext.HttpContext.Response.StatusCode == 401)
{
filterContext.Result = new RedirectResult("/");
}
}
}
AuthorizeAttribute的OnAuthorization方法内部调用了AuthorizeCore方法,这个方法是实现验证和授权逻辑的地方,如果这个方法返回true,
表示授权成功,如果返回false, 表示授权失败, 会给上下文设置一个HttpUnauthorizedResult,这个ActionResult执行的结果是向浏览器返回
一个401状态码(未授权),但是返回状态码没什么意思,通常是跳转到一个登录页面,可以重写AuthorizeAttribute的
HandleUnauthorizedRequest
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context == null)
{
throw new ArgumentNullException("filterContext");
}
else
{
string path = context.HttpContext.Request.Path;
string strUrl = "/Account/LogOn?returnUrl={0}";
context.HttpContext.Response.Redirect(string.Format(strUrl, HttpUtility.UrlEncode(path)), true);
}
}
MVC3 全局验证、过滤
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new System.Web.Mvc.AuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
1、首先定义一个全局类:
OAuth关注的是authorization;而OpenID侧重的是authentication。从表面上看,这两个英文单词很容易混淆,但实际上,它们的含义有本质的区别:
authorization: n. 授权,认可;批准,委任
authentication: n. 证明;鉴定;证实
OAuth关注的是授权,即:“用户能做什么”;而OpenID关注的是证明,即:“用户是谁”。下面就分别来说两者的功能。
OpenID
用户希望访问其在example.com的账户
example.com (在OpenID的黑话里面被称为“Relying Party”) 提示用户输入他/她/它的OpenID
用户给出了他的OpenID,比如说”http://user.myopenid.com”
example.com 跳转到了用户的OpenID提供商“mypopenid.com”
用户在”myopenid.com”(OpenID provider)提示的界面上输入用户名密码登录
“myopenid.com” (OpenID provider) 问用户是否要登录到example.com
用户同意后,”myopenid.com” (OpenID provider) 跳转回example.com
example.com 允许用户访问其帐号
OAuth
用户在使用example.com时希望从mycontacts.com导入他的联系人
example.com (在OAuth的黑话里面叫“Consumer”)把用户送往mycontacts.com (黑话是“Service Provider”)
用户在mycontacts.com 登录(可能也可能不用了他的OpenID)
mycontacts.com问用户是不是希望授权example.com访问他在mycontact.com的联系人
用户确定
mycontacts.com 把用户送回example.com
example.com 从mycontacts.com拿到联系人
example.com 告诉用户导入成功
OpenID是用来验证的,就是说可以用一个url来唯一表明身份(不用挨个记每个网站的用户密码)。OAuth是用来授权的(俺可以授权一个网站访问俺在另外一个网站的数据,而俺不用把俺的密码给第一个网站。
public static void RegisterAuth()
{
OAuthWebSecurity.RegisterFacebookClient(//配置OAuth
appId: "123456789012",
appSecret: "sldifemnivniesasx");
}
[RequireHttps]//所有调用都通过Https进行传输,这反过来导致白提供器使用HTTPS回调到我们的网站。Google和HTTPS一起使用是很重要的。Google会通过HTTP报告一个登录用户,而后对于两个不同的用户,会通过HTTPS报告。使用HTTPS就没有这个问题
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl=returnUrl;
return View();
}
{
@Html.AntiForgeryToken()
@:网站公告:<input type= " text " name= " Notice " id= " Notice " />
<input type= " submit " value= " Submit " />
}
对应的Action
[ValidateAntiForgeryToken]
public ActionResult Text()
{
ViewBag.Notice = Request.Form[ " Notice "].ToString();
return View();
}