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


  • 相关阅读:
    “三路九招”打赢电商低成本营销战
    我的文章分类
    ResourceBundle读取中文properties文件问题
    敏捷基础知识
    一个简单方法:构造xml的document,并将其转换为string
    在android源码环境下写上层应用的一个初步解决方法
    Linux 与 unix shell编程指南——学习笔记
    git 分支的基本操作
    使用repo的本地开发流程
    Linux常用命令收集
  • 原文地址:https://www.cnblogs.com/zengwei/p/11104301.html
Copyright © 2020-2023  润新知