asp.net web api 授权功能

1、重写授权方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Security;
using WebAPI.Models;
using WebAPI.Toolkit; namespace WebAPI.Filter
{
/// <summary>
/// 授权
/// </summary>
public class RequestAuthorizeAttribute:AuthorizeAttribute
{
/// <summary>
/// 重写授权方法,加入自定义的Ticket验证
/// </summary>
/// <param name="actionContext"></param>
public override void OnAuthorization(HttpActionContext actionContext)
{
var isActionAnonymous = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>().Any(a => a is AllowAnonymousAttribute);
var isControllerAnonymous = actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>().Any(a => a is AllowAnonymousAttribute); //如果控制器和动作上允许匿名访问
if (isControllerAnonymous || isActionAnonymous)
{
base.OnAuthorization(actionContext);
}
else
{
//从http请求的头里面获取身份验证信息,验证是否是请求发起方的ticket
var headers = actionContext.Request.Headers;
if ((headers.Authorization != null) && (headers.Authorization.Parameter != null))
{
//解密用户ticket,并校验用户名密码是否匹配
if (ValidateTicket(headers))
{
base.IsAuthorized(actionContext);
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
} /// <summary>
/// 校验用户身份
/// </summary>
/// <param name="headers">请求头</param>
/// <returns></returns>
private bool ValidateTicket(HttpRequestHeaders headers)
{
//解密Ticket
var strTicket = FormsAuthentication.Decrypt(headers.Authorization.Parameter).UserData; //从Ticket里面获取用户名和密码
var index = strTicket.IndexOf("&");
string userName = strTicket.Substring(, index);
//string password = strTicket.Substring(index + 1); //获取令牌
var token = headers.GetValues("AppId").FirstOrDefault(); //根据令牌和用户名得到键
string key = string.Format("{0}_{1}", token, userName); //根据缓存键拿到用户信息
var userInfo = CacheHelper.GetCache(key);
if (userInfo==null)
{
return false;
}
return true;
} /// <summary>
/// 重写授权失败响应
/// </summary>
/// <param name="actionContext"></param>
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
base.HandleUnauthorizedRequest(actionContext); actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, new ResultModel { Status = false, Data = null, ErrorMessage = "您没有权限访问资源" });
} }
}

2、基类控制器添加授权特性

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using WebAPI.Filter;
using System.IO;
using WebAPI.Models;
using System.Text;
using WebAPI.Toolkit; namespace WebAPI.Controllers
{
/// <summary>
/// 接口基类
/// </summary>
[Result]
[RequestAuthorize]
public class BaseApiController : ApiController
{
/// <summary>
/// 接口令牌
/// </summary>
protected string _token;
/// <summary>
///
/// </summary>
protected ApiClient _client;
/// <summary>
/// 接口配置
/// </summary>
public List<ApiModel> Apis
{
get
{
string path = string.Format("{0}/config.json", AppDomain.CurrentDomain.BaseDirectory);
string result = "";
if (File.Exists(path))
{
result = File.ReadAllText(path);
}
return JsonConvert.DeserializeObject<List<ApiModel>>(result);
}
} /// <summary>
/// 重写接口执行方法
/// </summary>
/// <param name="controllerContext">控制器上下文</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext,CancellationToken cancellationToken)
{
try
{
var header = controllerContext.Request.Headers;
_token = header.GetValues("AppId").FirstOrDefault();//接口令牌
string baseAddress = Apis.FirstOrDefault(a => a.Id == _token).Url; _client = new ApiClient(baseAddress, _token, header);
}
catch
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent(JsonConvert.SerializeObject(new ResultModel() { ErrorMessage = "未经授权" }), Encoding.UTF8, "application/json"); var source = new TaskCompletionSource<HttpResponseMessage>();
source.SetResult(response);
return source.Task;
}
return base.ExecuteAsync(controllerContext, cancellationToken);
} }
}

3.登录

using AppViewModel;
using AppViewModel.System;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Security;
using WebAPI.Models;
using WebAPI.Toolkit; namespace WebAPI.Controllers.System
{
/// <summary>
/// 用户信息
/// </summary>
public class UserController : BaseApiController
{
#region 登录 /// <summary>
/// 登录
/// </summary>
/// <param name="viewModel">登录实体</param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public UserViewModel Login([FromBody]LoginViewModel viewModel)
{
var result = _client.Post(viewModel, "api/SysUser/Login"); string ticket = string.Empty;
string key = string.Format("{0}_{1}", _token, viewModel.UserName); var userTicket = CacheHelper.GetCache(key);
if (userTicket == null)
{
//生成票据,通常是对用户名和密码进行编码,此处通过用户名和用户名编码进行混淆
var formTicket = new FormsAuthenticationTicket(, viewModel.UserName, DateTime.Now, DateTime.Now.AddHours(), true, string.Format("{0}&{1}", viewModel.UserName, viewModel.UserName), FormsAuthentication.FormsCookiePath);
//对票据进行加密
ticket = FormsAuthentication.Encrypt(formTicket);
CacheHelper.SetCache(key, ticket, DateTime.Now.AddHours());
}
else
{
ticket = userTicket.ToString();
} var userModel = new UserViewModel
{
Id = result.Data.Id,
OrgId = result.Data.所属机构Id,
Name = result.Data.真实姓名,
Account = result.Data.用户名,
Token = ticket
}; //获取App用户主题
var userTheme = _client.Get(string.Format("api/SysUserClientConfig/GetByUid?Uid={0}", userModel.Id));
userModel.ThemeName = (userTheme.Data == null) ? "" : userTheme.Data.ThemeName; GetUserPosts(userModel); GetUserModules(userModel); return userModel;
} /// <summary>
/// 获取用户岗位列表
/// </summary>
/// <param name="userModel"></param>
private void GetUserPosts(UserViewModel userModel)
{
var postResult = _client.Get(string.Format("api/SysBasicPost/GetByUid?Uid={0}", userModel.Id));
if (postResult.Data == null)
{
return;
}
foreach (var item in postResult.Data)
{
userModel.UserPosts.Add(new PostViewModel() { Id = item.Id, Name = item.岗位名称 });
}
} /// <summary>
/// 获取用户模块列表
/// </summary>
/// <param name="userModel"></param>
private void GetUserModules(UserViewModel userModel)
{
if (userModel.UserPosts.Count < || userModel.UserPosts.Count > )
{
return;
} //默认如果当前用户只有一个岗位就加载用户的模块列表
var result = _client.Get(string.Format("api/SysModule/Get?Gid={0}&Uid={1}&Pid={2}", userModel.OrgId, userModel.Id, userModel.UserPosts.FirstOrDefault().Id));
if (result.Data == null)
{
return;
} var viewModels = new List<ModuleViewModel>();
foreach (var item in result.Data)
{
viewModels.Add(new ModuleViewModel()
{
Id = item.Id,
PId = item.Pid,
Name = item.别名,
Url = item.默认入口页面,
IconUrl = item.图标URL
});
} userModel.UserModules = viewModels.Where(a => a.PId == null).ToList();
if (userModel.UserModules == null || userModel.UserModules.Count < )
{
return;
} //包装模块列表
foreach (var item in userModel.UserModules)
{
item.Childs = viewModels.Where(a => a.PId == item.Id).ToList();
}
} #endregion /// <summary>
/// 获取用户列表
/// </summary>
/// <param name="queryModel">机构Id、岗位Id</param>
/// <returns></returns>
[HttpPost]
public List<UserViewModel> GetUsers([FromBody]QueryBaseModel queryModel)
{
var result = _client.Get(string.Format("api/SysUser/GetByGidAndPid?Gid={0}&Pid={1}", queryModel.OrgId, queryModel.PostId));
if (result.Data==null)
{
return null;
} var viewModels = new List<UserViewModel>();
foreach (var item in result.Data)
{
viewModels.Add(new UserViewModel(){ Id = item.Id, Name = item.真实姓名 });
}
return viewModels;
} /// <summary>
/// 获取用户详情
/// </summary>
/// <param name="userId">用户Id</param>
/// <returns></returns>
[HttpPost]
public UserViewModel GetUserInfo([FromBody]int userId)
{
var result = _client.Get(string.Format("api/SysUser/GetById?Id={0}", userId));
if (result.Data == null)
{
return null;
} var viewModel = new UserViewModel()
{
Id = result.Data.Id,
Name = result.Data.真实姓名,
Tel = result.Data.手机,
Sex = result.Data.性别,
Email = result.Data.Email
};
return viewModel;
} }
}

登录参考基础认证的方式,但是为了和网上基础认证做区别没有对用户名和密码进行加密,而是针对用户名和用户名进行加密,加密的核心我认为是打破常规为原则。

如果某个接口不需要授权,则控制器或动作上方添加 [AllowAnonymous] 特性。

注意点:如果重写授权方法没有处理好匿名特性的逻辑,会导致不该认证的接口,打上匿名特性也照样走认证流程。

上一篇:blktrace分析IO


下一篇:Meta也很强