ASP.NET MVC View 和 Web API 的基本权限验证

ASP.NET MVC 5.0已经发布一段时间了,适应了一段时间,准备把原来的MVC项目重构了一遍,先把基本权限验证这块记录一下。

环境:Windows 7 Professional SP1 + Microsoft Visual Studio 2013(MVC 5 + Web API 2)

修改Web.config,增加Forms验证模式,在system.web节点中增加以下配置:

<authentication mode="Forms">

  <forms loginUrl="~/login" defaultUrl="~/" protection="All" timeout="20" name="__auth" />

</authentication>

【MVC View Controller 篇】

新建一个PageAuth,继承自AuthorizeAttribute:

using System;

using System.Net;

using System.Web;

using System.Web.Mvc;

using System.Web.Security;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]

public class PageAuth : AuthorizeAttribute

{

    protected override bool AuthorizeCore(HttpContextBase httpContext)

    {

        if (httpContext == null)

        {

            return false;

        }



        if (httpContext.User.Identity.IsAuthenticated && base.AuthorizeCore(httpContext))

        {

            return ValidateUser();

        }



        httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;

        return false;

    }



    public override void OnAuthorization(AuthorizationContext filterContext)

    {

        base.OnAuthorization(filterContext);



        if (filterContext.HttpContext.Response.StatusCode == (int)HttpStatusCode.Forbidden)

        {

            filterContext.Result = new RedirectToRouteResult("AccessErrorPage", null);

        }

    }



    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)

    {

        filterContext.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl);

    }



    private bool ValidateUser()

    {

        //TODO: 权限验证

        return true;

    }

}

建一个Controller的基类PageBase,继承自Controller:

using System.Web.Mvc;
[PageAuth]

public class PageBase : Controller

{

}

所有View的Controller均继承自PageBase,不再继承自Controller。

继承PageBase之后,所有的Controller均需登录,给允许匿名访问的Controller(或Action)增加AllowAnonymous(以AccountController为例):

using System.Web.Mvc;
public class AccountController : PageBase

{

    [AllowAnonymous]

    public ActionResult Login()  // 可匿名访问

    {

        ViewBag.Title = "用户登录";

        return View();

    }



    public ActionResult Detail(int id)   // 需登录访问

    {

        ViewBag.Title = "用户详情";

        return View();

    }

}

页面Controller的开发,基本结束,接下来就是在登录页面(~/login)使用js提交登录信息,用post方式提交。

提交之后,需要开发Web API的接口了。

【MVC Web API Controller 篇】

同样,新建一个ApiAuth,继承自ActionFilterAttribute:

using System;

using System.Net;

using System.Net.Http;

using System.Web.Http;

using System.Web.Http.Controllers;

using System.Web.Http.Filters;

using System.Web.Security;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]

public class ApiAuth : ActionFilterAttribute

{

    public override void OnActionExecuting(HttpActionContext actionContext)

    {

        try

        {

            if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0)   // 允许匿名访问

            {

                base.OnActionExecuting(actionContext);

                return;

            }



            var cookie = actionContext.Request.Headers.GetCookies();

            if (cookie == null || cookie.Count < 1)

            {

                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);

                return;

            }



            FormsAuthenticationTicket ticket = null;



            foreach (var perCookie in cookie[0].Cookies)

            {

                if (perCookie.Name == FormsAuthentication.FormsCookieName)

                {

                    ticket = FormsAuthentication.Decrypt(perCookie.Value);

                    break;

                }

            }



            if (ticket == null)

            {

                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);

                return;

            }



            // TODO: 添加其它验证方法



            base.OnActionExecuting(actionContext);

        }

        catch

        {

            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);

        }

    }

}

新建一个ApiController的基类ApiBase,继承自ApiController:

using System.Web.Http;
[ApiAuth]

public class ApiBase : ApiController

{

}

所有API的Controller均继承自ApiBase,不再继承自ApiController。

继承ApiBase之后,给允许匿名访问的Controller(或Action)增加AllowAnonymous(以LoginController为例):

using System.Web.Http;

using System.Web.Security;
public class LoginController : ApiBase

{

    [HttpPost]

    [AllowAnonymous]

    public bool Login([FromBody]LoginInfo loginInfo)

    {

        try

        {

            var cookie = FormsAuthentication.GetAuthCookie("Username", false);

            var ticket = FormsAuthentication.Decrypt(cookie.Value);

            var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, "");

            cookie.Value = FormsAuthentication.Encrypt(newTicket);

            DeyiContext.Response.Cookies.Add(cookie);return true;

        }

        catch

        {

            return false;

        }

    }

}

【写在最后】

网上查了很多方法,还需要时间验证一下各个方法的合理度。

关于Web API的安全性,个人觉得,还是采用SSL的方式更加稳妥一些。

另外,网上很多写的在Web API的权限判断的时候,使用的是actionContext.Request.Headers.Authorization来判断,如下:

if (actionContext.Request.Headers.Authorization == null)

{

    // 判断是否允许匿名访问

}

else

{

    var ticket = FormsAuthentication.Decrypt(actionContext.Request.Headers.Authorization.Parameter);

    // 后续其它验证操作

}

还没有完成测试该方法,慢慢来吧~~~

你可能感兴趣的:(asp.net)