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 ...
随机推荐
- react中为什么要使用immutable
因为在react中,react的生命周期中的setState()之后的shouldComponentUpdate()阶段默认返回true,所以会造成本组件和子组件的多余的render,重新生成virt ...
- Python 数据类型--Bytes类型
一.Bytes类型 在Python3以后,字符串和bytes类型彻底分开了.字符串是以字符为单位进行处理的,bytes类型是以字节为单位处理的. bytes数据类型在所有的操作和使用甚至内置方法上和字 ...
- pyqt5 使用 QTimer, QThread, pyqtSignal 实现自动执行,多线程,自定义信号触发。
渣渣用法,请等待我心情好的时候更新. 1.第一个例子 1.1 先看mainwindow.py from PyQt5 import QtCore, QtGui, QtWidgets class Ui_M ...
- slice,Array.prototype.slice,Array.protyotype.slice.call
slice 特点:基于当前数组中的一或多个项创建一个新数组.[原数组不会被修改] 返回结果:返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象. 语法: arr.slice() ...
- OO面向对象多线程编程作业总结
第五次作业:多线程电梯调度 设计策略 在本次电梯作业当中,我构造了一个电梯请求队列线程,一个调度器线程,三个电梯线程,一个文件输出线程,还有主线程. 调度器扫描用户的请求队列,将每个队列分配给 ...
- HDU 3455
http://acm.hdu.edu.cn/showproblem.php?pid=3435 同下题,只是这题是双向边,同时让我认识到了一个问题,一个图拆点做二分图完美匹配的本质是求该图环的并 htt ...
- Python CAN
/********************************************************************************* * Python CAN * 说明 ...
- Texas Instruments matrix-gui-2.0 hacking -- generate.php
<?php /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistrib ...
- 【error】Invalid ADAPTORNAME specified. Type 'imaqhwinfo' for a list of available ADAPTORNAMEs.
前言 使用matlab通过摄像头获取图像进行处理: 问题描述 使用matalb调用摄像头时出现错误: >> imaqhwinfo Warning: No Image Acquisition ...
- 结构体内的函数与bfs的情景变量
关于结构体内的函数,太难的尚且不会用,下面是一个简单一点的结构体内函数的代码 定义这样一个结构体函数之后就能像如下这样使用了 以上为结构体内的简单函数,下面重点来了,关于bfs找最短路由于需要避免走回 ...