c# webapi 过滤器token、sign认证、访问日志

1、token认证

服务端登录成功后分配token字符串。记录缓存服务器,可设置有效期

var token = Guid.NewGuid().ToString().Replace("-", "");
var expire = DateTime.Now.AddHours(2);
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=0,
        Driver=1
    }  

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 = 0
    }

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();
        }
    }


原文地址:https://www.cnblogs.com/zengwei/p/11104301.html