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] 特性。
注意点:如果重写授权方法没有处理好匿名特性的逻辑,会导致不该认证的接口,打上匿名特性也照样走认证流程。
asp.net web api 授权功能的更多相关文章
- 基于JWT(Json Web Token)的ASP.NET Web API授权方式
token应用流程 初次登录:用户初次登录,输入用户名密码 密码验证:服务器从数据库取出用户名和密码进行验证 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT 返还JWT ...
- OData services入门----使用ASP.NET Web API描述
http://www.cnblogs.com/muyoushui/archive/2013/01/27/2878844.html ODate 是一种应用层协议,设计它的目的在于提供一组通过HTTP的交 ...
- ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...
- ASP.NET Web API自身对CORS的支持: CORS授权检验的实施
通过<EnableCorsAttribute特性背后的故事>我们知道:由CorsPolicyProvider提供的CorsPolicy表示目标Action采用的资源授权策略,ASP.NET ...
- ASP.NET Web API Model-ParameterBinding
ASP.NET Web API Model-ParameterBinding 前言 通过上个篇幅的学习了解Model绑定的基础知识,然而在ASP.NET Web API中Model绑定功能模块并不是被 ...
- 使用 SoapUI 测试ASP.NET Web API
我们为不同的目的开发了很多web服务,经过授权的用户就可以访问和使用这些web服务.soapUI 是一个强大的测试web服务的工具,他不仅可以测试SOAP服务,他也支持测试RESTful服务.在这里我 ...
- 跨域资源共享(CORS)在ASP.NET Web API中是如何实现的?
在<通过扩展让ASP.NET Web API支持W3C的CORS规范>中,我们通过自定义的HttpMessageHandler自行为ASP.NET Web API实现了针对CORS的支持, ...
- 新作《ASP.NET Web API 2框架揭秘》正式出版
我觉得大部分人都是“眼球动物“,他们关注的往往都是目光所及的东西.对于很多软件从业者来说,他们对看得见(具有UI界面)的应用抱有极大的热忱,但是对背后支撑整个应用的服务却显得较为冷漠.如果我们将整个“ ...
- ASP.NET Web API 2框架揭秘
ASP.NET Web API 2框架揭秘(.NET领域再现力作顶级专家精讲微软全新轻量级通信平台) 蒋金楠 著 ISBN 978-7-121-23536-8 2014年7月出版 定价:108.0 ...
随机推荐
- Andriod Studio 解决问题 Failed to resolve: com.android.support:appcompat-v7:28.+
Andriod Studio报错提示: Error:(26, 13) Failed to resolve: com.android.support:appcompat-v7:28.+ 原因:Andri ...
- Thrift之双向通讯
在实际应用中,却经常会有客户端建立连接后,等待服务端数据的长连接模式,也可以称为双向连接.一.双连接,服务端与客户端都开ThriftServer如果网络环境可控,可以让服务端与客户端互相访问,你可以给 ...
- conan-transit服上的库列表
conan-transit服上的库列表 因为获取列表比较慢,所以获取后在此记录,以备查找.conan-transit 是个只读库,不会有更新.新的库将上传到 conan-center. conan是C ...
- 使用dig命令解析域名
Linux下解析域名除了使用nslookup之外,开可以使用dig命令来解析域名,dig命令可以得到更多的域名信息. dig的全称是 (domain information groper).它是一个用 ...
- 解决python3读写中文txt时UnicodeDecodeError : 'ascii' codec can't decode byte 0xc4 in position 5595: ordinal not in range(128) on line 0的问题
今天使用python3读写含有中文的txt时突然报了如下错误,系统是MAC OS,iDE是pycharm: UnicodeDecodeError : 'ascii' codec can't decod ...
- Windows下C++删除清除map
清除单map(非嵌套map) #include<map> #include<string> #include<iostream> using namespace s ...
- Windows-CreateProcess-lpsiStartInfo-STARTUPINFO-dwFlags
dwFlags: 简单地告诉CreateProcess函数结构中哪些成员有效: STARTF_USESIZE:使用dwXSize和dwYSize STARTF_USESHOWWINDOWS: wSho ...
- BZOJ1076: [SCOI2008]奖励关【状压DP+期望DP】
Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物, 每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的 ...
- Alternative Thinking 找规律
Kevin has just recevied his disappointing results on the USA Identification of Cows Olympiad (USAICO ...
- 数据库表结构转成设计书,PowerDesigner 表格导出为excel
数据库中的表导入到PowerDesigner中并转为excel文档 1.打开PowerDesigner12,在菜单中按照如下方式进行操作 file->Reverse Engineer->D ...