webapi框架搭建系列博客
上一篇已经完成了“身份验证”,如果只是想简单的实现基于角色的权限管理,我们基本上不用写代码,微软已经提供了authorize特性,直接用就行。
Authorize特性的使用方法
配置Authorize
比较简单,直接上代码
using System.Collections.Generic; using System.Net.Http; using System.Security.Claims; using System.Web.Http; using webapi.Common; namespace webapi.example { [RoutePrefix("api/security")] public class SecurityTestController : ApiController { /// <summary> /// 通过get请求里传过来的值生成token /// </summary> /// <returns></returns> [Route("token"),HttpGet] public IHttpActionResult GetToken() { var dic=new Dictionary<string,object>(); foreach (var queryNameValuePair in Request.GetQueryNameValuePairs()) { dic.Add(queryNameValuePair.Key,queryNameValuePair.Value); } var token=new JWTHelper().Encode(dic, "shengyu",30); return Ok(token); } /// <summary> /// 返回token里加密的信息 /// </summary> /// <returns></returns> [Route("GetUserInfoFromToken"),HttpGet] public IHttpActionResult GetUser() { var user = (ClaimsPrincipal)User; var dic=new Dictionary<string,object>(); foreach (var userClaim in user.Claims) { dic.Add(userClaim.Type,userClaim.Value); } return Ok(dic); } #region 硬编码的方式实现简单的权限控制 /// <summary> /// 只有某种角色的用户才有权限访问 /// </summary> /// <returns></returns> [Route("byCode/onlyRoles"), Authorize(Roles = "admin,superAdmin"),HttpGet] public IHttpActionResult OnlyRoles_SetByCode() { return Ok("OnlyRoles_SetByCode,仅管理员能访问"); } /// <summary> /// 只有某几个用户才有权限访问 /// </summary> /// <returns></returns> [Route("byCode/onlyUsers"), Authorize(Users = "张三,李四"),HttpGet] public IHttpActionResult OnlyUsers_SetByCode() { return Ok("OnlyRoles_SetByCode,仅张三和李四才能访问"); } #endregion } }
Authorize特性有Roles和Users两个属性,设置这两个属性的值及可以控制哪些角色/用户有权限访问。Authorize特性可以用于修饰类或是方法,如果整个控制器都要用权限控制,则修饰这个控制器类,否则只修饰在某个接口上。如果控制器被修饰了但又要排除某一个action,可用AllowAnonymous特性进行排除。
获取token
现在获取一个token,这个token里包含了“角色为admin”的信息,如下
用上一篇:webapi框架搭建-安全机制-身份验证(二)里的获取token的接口获取一个role为admin的token
请求需要权限的接口
请求需要角色为admin或是superAdmin的接口SecurityTestController.OnlyRoles_SetByCode(),注意将上一步生成的token放到http request的header里
你可尝试在“获取token"步骤里生成非admin角色的token,那么在这一步里会出现授权失败的错误,如下图
同样原理,在”获取token"步骤里user设置成“张三”或“李四”时,就可以用此token访问SecurityTestController.OnlyUsers_SetByCode()接口了。
在实际开发中,获取token的接口(即方法SecurityTestController.GetToken())里的代码通常写在用户登录接口里,用户通过用户名和密码登录成功后,接口访问一个token给客户端,以后客户端的每次接口请求都在headers里带上这个token。微软提供的默认authorize特性在小项目和中型的对权限控制没有复杂要求的项目里已经够用了。缺点是项目开发前得确定好业务的各种角色,因为要以“硬编码”的方式写在接口方法上。后期如果要修改一个接口的所属角色,只有重新修改代码。
如果要实现更加可控的基于角色的权限控制,只有自己写Authorize filter。下面介绍如何写自己的authorize filter。
自定义Authorize filter
可通过继承下面三个对象之一去写自己的authorize filter
即:AuthorizeAttribute、AuthorizationFilterAttribute、IAuthorizationFilter,三者的关系如下图
我采用继承AuthorizeAttribute,并重写IsAuthorized方法,代码如下
using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Http.Controllers; namespace webapi.Security { /// <summary> /// Role Basic AuthorizeAttribute(基于角色的授权) /// </summary> public class RBAuthorizeAttribute:AuthorizeAttribute { protected override bool IsAuthorized(HttpActionContext actionContext) { // 下在可替换成自己的授权逻辑代码 return base.IsAuthorized(actionContext); } protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "未授权"); } } }
RBAuthorize特性和Authorize特性用法是一样的,不再重复。后续的博客里会引入基于角色的权限管理的表结构,并在IsAuthorized方法里写授权逻辑。