c# webapi 过滤器token、sign认证、访问日志
1、token认证
服务端登录成功后分配token字符串。记录缓存服务器,可设置有效期
var token = Guid.NewGuid().ToString().Replace("-", "");
var expire = DateTime.Now.AddHours();
var timespan = ( expire- DateTime.Now);
var key = string.Format("login-{0}", apiRm.Result.UserID);
RedisCacheHelper.SetCacheByKey<string>(key, JsonHelper.ToJson(apiRm.Result), timespan);
通过header传入token后进行服务端认证有效性
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'token: 1000-e0622f06a9a842a5b79a5295e6d4b235' -d
在controller或action可设置属性是否要验证token
controller:[RoutePrefix("api/Out"), OperateTrack, AuthToken(AuthTypeEnum.Driver)]
或
action:[HttpPost, Route("GetOutInfo"),AuthToken(AuthTypeEnum.Driver)]
读取过滤器传过来的信息:
var user = ControllerContext.RouteData.Values["user"];
var user1 = HttpContext.Current.User;
创建AuthTokenAttribute继承AuthorizeAttribute
public class AuthTokenAttribute : AuthorizeAttribute
{
public AuthTypeEnum VerifyAuth { get; set; } public AuthTokenAttribute() { this.VerifyAuth = AuthTypeEnum.Common; } public AuthTokenAttribute(AuthTypeEnum verifyAuth)
{
this.VerifyAuth = verifyAuth;
} protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var request = actionContext.Request;
if(VerifyAuth== AuthTypeEnum.Driver)
{
var rm= AuthDriver(actionContext);
if (!rm.IsSuccess)
return false;
}
return true;
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
StringBuilder sbMsg = new StringBuilder();
if (VerifyAuth == AuthTypeEnum.Driver)
{
var rm = AuthDriver(actionContext);
if (!rm.IsSuccess)
sbMsg.Append(rm.Message);
}
var content = JsonConvert.SerializeObject(new ResultApiModel { IsSuccess = false, Message = sbMsg.ToString() + ",验证失败,状态:" + (int)HttpStatusCode.Unauthorized, Code = ((int)HttpStatusCode.Unauthorized).ToString() });
actionContext.Response = new HttpResponseMessage
{
Content = new StringContent(content, Encoding.UTF8, "application/json"),
StatusCode = HttpStatusCode.Unauthorized
};
} private ResultApiModel AuthDriver(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//todo 验证token
//向action传值,在action中可以使用:var user = ControllerContext.RouteData.Values["user"];获取到
actionContext.ControllerContext.RouteData.Values["user"] = v;
SetPrincipal(new UserPrincipal<int>(tokenV));
return ResultApiModel.Create(true);
}
public static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
//每次都重新覆盖user,避免不同用户对不同action的访问
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
}
public enum AuthTypeEnum
{
Common=,
Driver=
} IPrincipal:
public class UserIdentity<TKey> : IIdentity
{
public UserIdentity(IUser<TKey> user)
{
if (user != null)
{
IsAuthenticated = true;
UserID = user.UserID;
LoginNo = user.LoginNo.ToString();
Name = user.LoginNo.ToString();
UserName = user.UserName;
RoleCode = user.RoleCode;
token = user.token;
}
} public string AuthenticationType
{
get { return "CustomAuthentication"; }
} public TKey UserID { get; private set; } public bool IsAuthenticated { get; private set; } public string LoginNo { get; private set; } public string Name { get; private set; } public string UserName { get; private set; } public string RoleCode { get; private set; } public string token { get; private set; }
} public class UserPrincipal<TKey> : IPrincipal
{
public UserPrincipal(UserIdentity<TKey> identity)
{
Identity = identity;
} public UserPrincipal(IUser<TKey> user)
: this(new UserIdentity<TKey>(user))
{ } /// <summary>
///
/// </summary>
public UserIdentity<TKey> Identity { get; private set; } IIdentity IPrincipal.Identity
{
get { return Identity; }
} bool IPrincipal.IsInRole(string role)
{
throw new NotImplementedException();
}
} public interface IUser<T>
{
/// <summary>
/// 用户id
/// </summary>
T UserID { get; set; } /// <summary>
/// 登录账号
/// </summary>
string LoginNo { get; set; }
/// <summary>
/// 用户名称
/// </summary>
string UserName { get; set; }
/// <summary>
/// 角色编号
/// </summary>
string RoleCode { get; set; } /// <summary>
/// 登录后分配token
/// </summary>
string token { get; set; }
}
2、验证签名:
约定签名规则
controller或action增加属性验证
[AuthSign(AuthSignTypeEnum.Common)]
创建AuthSignAttribute继承AuthorizeAttribute
public class AuthSignAttribute : AuthorizeAttribute
{
public AuthSignTypeEnum AuthSignType { get; set; }
public AuthSignAttribute() { this.AuthSignType = AuthSignTypeEnum.Common; }
public AuthSignAttribute(AuthSignTypeEnum authSignType)
{
this.AuthSignType = authSignType;
}
/// <summary>
/// 公共请求主体数据
/// </summary>
private string CommonRequestBodyData { get; set; } /// <summary>
/// 权限验证
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var request = actionContext.Request;
var requestBodyData = StreamHelper.GetStream2String(request.Content.ReadAsStreamAsync().Result);
if (AuthSignType == AuthSignTypeEnum.Common)
{
CommonRequestBodyData = requestBodyData.TrimStart("data=".ToCharArray());
var urlParam = GetUrlParam(actionContext);
if (!urlParam.IsSuccess) return false;
var rm = AuthSignCommon(urlParam.Result, CommonRequestBodyData);
if (!rm.IsSuccess)
return false;
} return true;
} private ResultApiModel AuthSignCommon(CommonRequestApiModel request, string requestBodyData)
{
//todo 验证signreturn ResultApiModel.Create(true);
}/// <summary>
/// 处理未授权的请求
/// </summary>
/// <param name="actionContext"></param>
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
StringBuilder sbMsg = new StringBuilder();
if (AuthSignType == AuthSignTypeEnum.Common)
{
//todo 处理验证失败信息
}
var content = JsonConvert.SerializeObject(new ResultApiModel { IsSuccess = false, Message = sbMsg.ToString() + " 签名验证失败,状态:" + HttpStatusCode.Unauthorized });
actionContext.Response = new HttpResponseMessage
{
Content = new StringContent(content, Encoding.UTF8, "application/json"),
StatusCode = HttpStatusCode.Unauthorized
};
}
}
/// <summary>
/// 签名类型
/// </summary>
public enum AuthSignTypeEnum
{
Common =
}
3、访问日志:
controller或action增加属性
[RoutePrefix("api/Out"), OperateTrack, AuthToken(AuthTypeEnum.Driver)]
不需要日志可以[NoLog]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class NoLogAttribute : Attribute
{
}
继承:ActionFilterAttribute
public class OperateTrackAttribute : ActionFilterAttribute
{
/// <summary>
/// 自定义参数
/// </summary>
public string msg { get; set; }
public OperateTrackAttribute()
{ } /// <summary>
/// 初始化时填入类的说明
/// </summary>
/// <param name="message"></param>
public OperateTrackAttribute(string message)
{
msg = message;
} private static readonly string key = "enterTime";
public override Task OnActionExecutingAsync(System.Web.Http.Controllers.HttpActionContext actionContext, CancellationToken cancellationToken)
{
if (SkipLogging(actionContext))
{
return base.OnActionExecutingAsync(actionContext, cancellationToken); }
//记录进入请求的时间
actionContext.Request.Properties[key] = DateTime.Now.ToBinary(); return base.OnActionExecutingAsync(actionContext, cancellationToken);
}
/// <summary>
/// 在请求执行完后 记录请求的数据以及返回数据
/// </summary>
/// <param name="actionExecutedContext"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
object beginTime = null;
if (actionExecutedContext.Request.Properties.TryGetValue(key, out beginTime))
{
DateTime time = DateTime.FromBinary(Convert.ToInt64(beginTime));
HttpRequest request = HttpContext.Current.Request;
string token = request.Headers["token"]; WebApiActionLogModel apiActionLog = new WebApiActionLogModel
{
Id = Guid.NewGuid(),
//获取action名称
actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName,
//获取Controller 名称
controllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName,
//获取action开始执行的时间
enterTime = time,
//获取执行action的耗时
costTime = (DateTime.Now - time).TotalMilliseconds,
navigator = request.UserAgent,
token = token,
//获取用户token
userId = getUserByToken(token),
//获取访问的ip
ip = request.UserHostAddress,
userHostName = request.UserHostName,
urlReferrer = request.UrlReferrer != null ? request.UrlReferrer.AbsoluteUri : "",
browser = request.Browser.Browser + " - " + request.Browser.Version + " - " + request.Browser.Type,
//获取request提交的参数
paramaters = StreamHelper.GetStream2String(actionExecutedContext.Request.Content.ReadAsStreamAsync().Result),
//获取response响应的结果
executeResult = StreamHelper.GetStream2String(actionExecutedContext.Response.Content.ReadAsStreamAsync().Result),
comments = msg,
RequestUri = request.Url.AbsoluteUri
};
//记debug
Log.DefaultLogDebug(string.Format("actionExecutedContext {0} 请求:{1}", apiActionLog.controllerName + "/" + apiActionLog.actionName, JsonHelper.ToJson(apiActionLog)));
}
return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken); }
/// <summary>
/// 获取当前登录用户的id
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public static string getUserByToken(string token)
{
UserIdentity<int> u = HttpContext.Current.User.Identity as UserIdentity<int>;
if (u == null) return "未登录用户" + token;
return u.LoginNo.ToString();
} /// <summary>
/// 判断类和方法头上的特性是否要进行Action拦截
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
private static bool SkipLogging(System.Web.Http.Controllers.HttpActionContext actionContext)
{
return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any();
}
}
c# webapi 过滤器token、sign认证、访问日志的更多相关文章
- ASP.NET WebApi 基于OAuth2.0实现Token签名认证
一.课程介绍 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将是我们需要思考的问题.为了保护我们的WebApi数 ...
- ASP.NET WebApi 基于JWT实现Token签名认证
一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证(发布版)
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
- apache用户认证、域名跳转、Apache访问日志(两种格式)
1.apache 设置,用户访问时 目录或文件的认证: 对目录的认证: <Directory /var/www/222> //指定认证的目录AllowOverride AuthConfig ...
- centos LAMP第二部分apache配置 下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转 配置apache的访问日志 配置静态文件缓存 配置防盗链 访问控制 apache rewrite 配置开机启动apache tcpdump 第二十节课
centos LAMP第二部分apache配置 下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转 配置apache的访问日志 配置静态文件缓存 配置防盗链 ...
- Apache用户认证、域名跳转、Apache访问日志
5月29日任务 课程内容: 11.18 Apache用户认证11.19/11.20 域名跳转11.21 Apache访问日志扩展 apache虚拟主机开启php的短标签 http://ask.apel ...
- Linux CentOS7 VMware LAMP架构Apache用户认证、域名跳转、Apache访问日志
一.Apache用户认证 vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf //把111.com那个虚拟主机编辑成如下内容 <Virtu ...
- C# WebApi 过滤器的使用开发接口必备利器
在WEB Api中,引入了面向切面编程(AOP)的思想,在某些特定的位置可以插入特定的Filter进行过程拦截处理.引入了这一机制可以更好地践行DRY(Don’t Repeat Yourself)思想 ...
随机推荐
- 干货 | 10分钟带你全面掌握branch and bound(分支定界)算法-概念篇
00 前言 之前一直做启发式算法,最近突然对精确算法感兴趣了.但是这玩意儿说实话是真的难,刚好boss又叫我学学column generation求解VRP相关的内容.一看里面有好多知识需要重新把握, ...
- Python3菜鸟教程笔记
多行语句 同一行显示多条语句 Print 输出
- vscode快捷键,让你脱离鼠标,敲代码嗖嗖的
蓝色为本人需要经常用到的,可忽略 vsCode软件相关 显示资源管理器:Ctrl + Shift + E 显示搜索: Ctrl + Shift + F 显示git:Ctrl + Shift + G 显 ...
- 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数
今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...
- Spring Boot 面试,一个问题就干趴下了!(下)
前些天栈长在Java技术栈微信公众号分享一篇文章:Spring Boot 面试,一个问题就干趴下了!,看到大家的留言很精彩,特别是说"约定大于配置"的这两个玩家. 哈哈,上墙的朋友 ...
- @PathVariable不起作用,报错:Cannot resolve @PathVariable ' '
@PathVariable是占位符注解.可以把Url中变量的值传递到方法参数中. 示例如下: @PostMapping("/user/name/{id}") @ResponseBo ...
- tomcat启动报错java.lang.OutOfMemoryError:PermGen space解决办法
tomcat启动错误提示: 严重: Error waiting for multi-thread deployment of WAR files to completejava.util.concur ...
- 团队作业-Beta版本演示
组长博客链接 https://www.cnblogs.com/cmlei/p/12063671.html 本组成员 031702431 陈明磊 组长 031702227 林镕炜 031702413 韩 ...
- DELPHI7 ADO二层升三层新增LINUX服务器方案
DELPHI7 ADO二层升三层新增LINUX服务器方案 引子:笔者曾经无数次在用户的LINUX服务器上创建一个WINDOWS虚拟机,用于运行自己DELPHI开发中间件. 现在再不需要如此麻烦了. 咏 ...
- C++多线程下出现内存越界问题总结
工作中遇到这样一个问题,某个多级流水多线程的程序,在压力测试下会偶现segmentation fault11错误,错误出现在运行类函数的地方,而后排查后发现是由于多线程争抢导致类被析构后才走入判断,导 ...