5. WebApi 服务端代码示例
5.1 控制器基类ApiControllerBase
- ///
- /// Controller的基类,用于实现适合业务场景的基础功能
- ///
- ///
- [BasicAuthentication]
- public abstract class ApiControllerBase : ApiController
- {
- }
5.2 权限属性BaseAuthenticationAttribute
- ///
- /// 基本验证Attribtue,用以Action的权限处理
- ///
- public class BasicAuthenticationAttribute : ActionFilterAttribute
- {
- ///
- /// 检查用户是否有该Action执行的操作权限
- ///
- ///
- public override void OnActionExecuting(HttpActionContext actionContext)
- {
- //检验用户ticket信息,用户ticket信息来自调用发起方
- if (actionContext.Request.Headers.Authorization != null)
- {
- //解密用户ticket,并校验用户名密码是否匹配
- var encryptTicket = actionContext.Request.Headers.Authorization.Parameter;
- if (ValidateUserTicket(encryptTicket))
- base.OnActionExecuting(actionContext);
- else
- actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
- }
- else
- {
- //检查web.config配置是否要求权限校验
- bool isRquired = (WebConfigurationManager.AppSettings["WebApiAuthenticatedFlag"].ToString() == "true");
- if (isRquired)
- {
- //如果请求Header不包含ticket,则判断是否是匿名调用
- var attr = actionContext.ActionDescriptor.GetCustomAttributes().OfType();
- bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
- //是匿名用户,则继续执行;非匿名用户,抛出“未授权访问”信息
- if (isAnonymous)
- base.OnActionExecuting(actionContext);
- else
- actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
- }
- else
- {
- base.OnActionExecuting(actionContext);
- }
- }
- }
- ///
- /// 校验用户ticket信息
- ///
- ///
- ///
- private bool ValidateUserTicket(string encryptTicket)
- {
- var userTicket = FormsAuthentication.Decrypt(encryptTicket);
- var userTicketData = userTicket.UserData;
- string userName = userTicketData.Substring(0, userTicketData.IndexOf(":"));
- string password = userTicketData.Substring(userTicketData.IndexOf(":") + 1);
- //检查用户名、密码是否正确,验证是合法用户
- //var isQuilified = CheckUser(userName, password);
- return true;
- }
- }
5.3 api服务Controller实例
- public class ProductController : ApiControllerBase
- {
- [HttpGet]
- public object Find(string id)
- {
- return ProductServiceInstance.Find(2);
- }
- // GET api/product/5
- [HttpGet]
- [AllowAnonymous]
- public Product Get(string id)
- {
- var headers = Request.Headers;
- var p = ProductServiceInstance.GetById(long.Parse(id));
- if (p == null)
- {
- throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
- Content = new StringContent("id3 not found"), ReasonPhrase = "product id not exist." });
- }
- return p;
- }
- }
6. 其它配置说明
6.1 Mvc前端Web.Config 配置
- <</SPAN>system.web>
- <</SPAN>compilation debug="true" targetFramework="4.5">
- <</SPAN>assemblies>
- <</SPAN>add assembly="System.Web.Http.Data.Helpers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
- </</SPAN>assemblies>
- </</SPAN>compilation>
- <</SPAN>httpRuntime targetFramework="4.5" />
- <</SPAN>authentication mode="Forms">
- <</SPAN>forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All" timeout="90" name=".AuthCookie"></</SPAN>forms>
- </</SPAN>authentication>
- <</SPAN>machineKey validationKey="3FFA12388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
- </</SPAN>system.web>
machineKey节点配置,是应用于对用户ticket数据加密和解密。
6.2 WebApi服务端Web.Config配置
- <</SPAN>system.web>
- <</SPAN>machineKey validationKey="3FF112388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
- </</SPAN>system.web>
machineKey节点配置,是应用于对用户ticket数据加密和解密。
7. 总结
Web系统的用户登录及页面操作权限验证在处理逻辑上比较复杂,需要考虑到Form认证、匿名访问,Session和Cookie存储,以及Session和Cookie的过期处理,本文实现了整个权限验证框架的基本功能,供系统架构设计人员以及Web开发人员参考。
Demo项目代码地址:
https://github.com/lgsky/DemoUserAuthorization/