zoukankan      html  css  js  c++  java
  • ASP.NET MVC API 接口验证

    项目中有一个留言消息接口,接收其他系统的留言和展示留言,参考了网上的一些API验证方法,发现使用通用权限管理系统提供的验证方法最完美(http://www.cnblogs.com/jirigala/p/5506022.html)。

    下面将实现的完整思路共享

    1、WebApiConfig全局处理

        /// <summary>
        /// WebApiConfig 
        /// 路由基础配置。
        /// 
        /// 
        /// 修改记录
        /// 
        ///        2016.11.01 版本:2.0 宋彪 对日期格式进行统一处理。
        ///        2016.10.30 版本:2.0 宋彪 解决json序列化时的循环引用问题。
        ///        2016.10.28 版本:2.0 宋彪 回传响应格式 $format 支持。
        ///        2016.09.01 版本:1.0 宋彪   创建。
        /// 
        /// 版本:1.0
        /// 
        /// <author>
        ///        <name>宋彪</name>
        ///        <date>2016.09.01</date>
        /// </author> 
        /// </summary>
        public static class WebApiConfig
        {
            /// <summary>
            /// 注册全局配置服务
            /// </summary>
            /// <param name="config"></param>
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                //强制https访问
                //config.Filters.Add(new ForceHttpsAttribute());
                // 统一回传格式
                config.Filters.Add(new ApiResultAttribute());
                // 发生异常时处理
                config.Filters.Add(new ApiErrorHandleAttribute());
                // ToKen身份验证过滤器 更方便 不需要在这里了 具有改标签的就会自动检查
                //config.Filters.Add(new ApiAuthFilterAttribute());
                // 解决json序列化时的循环引用问题
                config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                //对日期格式进行统一处理
                config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(
                new IsoDateTimeConverter()
                {
                    DateTimeFormat = "yyyy-MM-dd hh:mm:ss"
                }
                );
    
                // Web API routes 路由
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                // 干掉XML序列化器
                //config.Formatters.Remove(config.Formatters.XmlFormatter);
                //在请求的Url加上 ?$format=xml,便可以指定响应格式
                config.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");
                config.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json");
            }
        }

    2、身份验证过滤器

        using DotNet.Business;
        using DotNet.Utilities;
        using DotNet.Tracking.API.Common;
    
        /// <summary>
        /// ApiAuthFilterAttribute
        /// 身份验证过滤器,具有ApiAuthFilterAttribute标签属性的方法会自动检查
        /// 
        /// 
        /// 修改纪录
        /// 
        /// 2016-10-11 版本:1.0 SongBiao 创建文件。   
        /// 
        /// <author>
        ///     <name>SongBiao</name>
        ///     <date>2016-10-11</date>
        /// </author>
        /// </summary>
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
        public class ApiAuthFilterAttribute : AuthorizationFilterAttribute
        {
            /// <summary>
            /// 未授权时的提示信息
            /// </summary>
            private const string UnauthorizedMessage = "请求未授权,拒绝访问。";
    
            /// <summary>
            /// 权限进入
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                base.OnAuthorization(actionContext);
                // 允许匿名访问
                if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0)  
                {
                    return;
                }
    
                string systemCode = APIOperateContext.Current.SystemCode;
                string permissionCode = APIOperateContext.Current.PermissionCode;
                string appKey = APIOperateContext.Current.AppKey;
                string appSecret = APIOperateContext.Current.AppSecret;            
                if (string.IsNullOrWhiteSpace(appKey) || string.IsNullOrWhiteSpace(appSecret))
                {
                    //未验证(登录)的用户, 而且是非匿名访问,则转向登录页面  
                    //actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                    //actionContext.Response.Content = new StringContent("<p>Unauthorized</p>", Encoding.UTF8, "text/html");
                    var response = actionContext.Response= actionContext.Response?? new HttpResponseMessage();
                    response.StatusCode = HttpStatusCode.Unauthorized;
                    BaseResult result = new BaseResult
                    {
                        Status = false,
                        StatusMessage = UnauthorizedMessage
                    };
                    response.Content = new StringContent(result.ToJson(), Encoding.UTF8, "application/json");
                }
                else
                {
                    // 检查 AppKey 和 AppSecret
                    BaseResult result = BaseServicesLicenseManager.CheckService(appKey, appSecret, false, 0, 0, systemCode, permissionCode);
                    if (!result.Status)
                    {
                        var response = actionContext.Response = actionContext.Response?? new HttpResponseMessage();
                        response.Content = new StringContent(result.ToJson(), Encoding.UTF8, "application/json");
                    }
                }
                         
            }
        }

    3、统一回传格式

        /// <summary>
        /// ApiResultAttribute
        /// 统一回传格式
        /// 
        /// 修改纪录
        /// 
        /// 2016-10-31 版本:1.0 宋彪 创建文件。
        /// 
        /// <author>
        ///     <name>宋彪</name>
        ///     <date>2016-10-31</date>
        /// </author>
        /// </summary>
        public class ApiResultAttribute : ActionFilterAttribute
        {
            /// <summary>
            /// 重写回传的处理
            /// </summary>
            /// <param name="actionExecutedContext"></param>
            public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
            {
                // 快件跟踪接口传的是format,不用走这里
                if (actionExecutedContext.Request.Properties.ContainsKey("format"))
                {
                    // 若发生例外则不在这边处理 在异常中处理 ApiErrorHandleAttribute
                    if (actionExecutedContext.Exception != null)
                        return;
                    base.OnActionExecuted(actionExecutedContext);
                    var result = new ApiResultModel();
                    // 取得由 API 返回的状态码
                    result.Status = actionExecutedContext.ActionContext.Response.StatusCode;
                    // 取得由 API 返回的资料
                    result.Data = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync<object>().Result;
                    // 重新封装回传格式
                    actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(result.Status, result);
                }
            }
        }

    4、全局异常处理

        using DotNet.Utilities;
        using DotNet.Tracking.API.Common;
        using DotNet.Tracking.API.Controllers;
        using DotNet.Tracking.API.Models;
    
        /// <summary>
        /// ApiErrorHandleAttribute
        /// 全局异常处理
        /// 
        /// 修改纪录
        /// 
        /// 2016-10-31 版本:1.0 宋彪 创建文件。
        /// 
        /// <author>
        ///     <name>宋彪</name>
        ///     <date>2016-10-31</date>
        /// </author>
        /// </summary>
    
        public class ApiErrorHandleAttribute : System.Web.Http.Filters.ExceptionFilterAttribute
        {
            /// <summary>
            /// 异常统一处理
            /// </summary>
            /// <param name="actionExecutedContext"></param>
            public override void OnException(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
            {
                base.OnException(actionExecutedContext);
                // 取得发生例外时的错误讯息
                var errorMessage = actionExecutedContext.Exception.Message;
    
                // 异常记录
                string parameters = APIOperateContext.GetRequestParameters();
                NLogHelper.Trace(actionExecutedContext.Exception, BaseSystemInfo.SystemCode + " ApiErrorHandleAttribute OnException 完整的请求地址及参数 : " + parameters);
                // 2016-11-01 加入异常邮件提醒
                NLogHelper.InfoMail(actionExecutedContext.Exception, BaseSystemInfo.SystemCode + " ApiErrorHandleAttribute OnException 完整的请求地址及参数 : " + parameters);
    
                var result = new ApiResultModel()
                {
                    Status = HttpStatusCode.BadRequest,
                    ErrorMessage = errorMessage
                };
                // 重新打包回传的讯息
                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(result.Status, result);
            }
        }

    5、接口操作的上下文

        using DotNet.Business;
        using DotNet.Model;
        using DotNet.Utilities;
    
        /// <summary>
        /// APIOperateContext
        /// 接口操作的上下文
        /// 跟上下文有关的一些通用的东西放在这里处理
        /// 
        /// 修改纪录
        /// 
        /// 2016-10-31 版本:1.0 宋彪 创建文件。
        /// 
        /// <author>
        ///     <name>宋彪</name>
        ///     <date>2016-10-31</date>
        /// </author>
        /// </summary>
        public class APIOperateContext
        {
            /// <summary>
            /// 获取当前 操作上下文 (为每个处理浏览器请求的服务器线程 单独创建 操作上下文)
            /// </summary>
            public static APIOperateContext Current
            {
                get
                {
                    APIOperateContext oContext = CallContext.GetData(typeof(APIOperateContext).Name) as APIOperateContext;
                    if (oContext == null)
                    {
                        oContext = new APIOperateContext();
                        CallContext.SetData(typeof(APIOperateContext).Name, oContext);
                    }
                    return oContext;
                }
            }
    
            #region Http上下文 及 相关属性
            /// <summary>
            /// Http上下文
            /// </summary>
            public HttpContext ContextHttp
            {
                get
                {
                    return HttpContext.Current;
                }
            }
    
            /// <summary>
            /// 输出对象
            /// </summary>
            public HttpResponse Response
            {
                get
                {
                    return ContextHttp.Response;
                }
            }
    
            /// <summary>
            /// 请求对象
            /// </summary>
            public HttpRequest Request
            {
                get
                {
                    return ContextHttp.Request;
                }
            }
    
            /// <summary>
            /// Session对象
            /// </summary>
            System.Web.SessionState.HttpSessionState Session
            {
                get
                {
                    return ContextHttp.Session;
                }
            }
            #endregion
    
            /// <summary>
            /// 获取全部请求参数,get和post的 简化版
            /// </summary>
            public static string GetRequestParameters()
            {
                string query = HttpContext.Current.Request.Url.Query;
                NameValueCollection nvc;
                string baseUrl;
                ParseUrl(query, out baseUrl, out nvc);
                List<string> list = new List<string>() { };
                foreach (var key in nvc.AllKeys)
                {
                    list.Add(key + "=" + nvc[key]);
                }
    
                var form = HttpContext.Current.Request.Form;
                foreach (var key in form.AllKeys)
                {
                    list.Add(key + "=" + form[key]);
                }
                string result = HttpContext.Current.Request.Url.AbsoluteUri + "?" + string.Join("&", list);
    
                return result;
            }
    
            /// <summary>
            /// 分析 url 字符串中的参数信息
            /// 针对get请求的
            /// </summary>
            /// <param name="url">输入的 URL</param>
            /// <param name="baseUrl">输出 URL 的基础部分</param>
            /// <param name="nvc">输出分析后得到的 (参数名,参数值) 的集合</param>
            public static void ParseUrl(string url, out string baseUrl, out NameValueCollection nvc)
            {
                if (url == null)
                {
                    throw new ArgumentNullException("url");
                }
                nvc = new NameValueCollection();
                baseUrl = "";
                if (url == "")
                {
                    return;
                }
                int questionMarkIndex = url.IndexOf('?');
                if (questionMarkIndex == -1)
                {
                    baseUrl = url;
                    return;
                }
                baseUrl = url.Substring(0, questionMarkIndex);
                if (questionMarkIndex == url.Length - 1)
                {
                    return;
                }
                string ps = url.Substring(questionMarkIndex + 1);
                // 开始分析参数对  
                Regex re = new Regex(@"(^|&)?(w+)=([^&]+)(&|$)?", RegexOptions.Compiled);
                MatchCollection mc = re.Matches(ps);
                foreach (Match m in mc)
                {
                    nvc.Add(m.Result("$2").ToLower(), m.Result("$3"));
                }
            }
    
            /// <summary>
            /// 系统编号
            /// </summary>
            public string SystemCode
            {
                get
                {
                    return Request["systemCode"] ?? "Base";
                }
            }
    
            /// <summary>
            /// 权限编号
            /// </summary>
            public string PermissionCode
            {
                get
                {
                    return Request["permissionCode"];
                }
            }
    
            /// <summary>
            /// 访问接口的应用传来AppKey
            /// </summary>
            public string AppKey
            {
                get
                {
                    return Request["appKey"];
                }
            }
    
            /// <summary>
            /// 访问接口的应用传来AppSecret
            /// </summary>
            public string AppSecret
            {
                get
                {
                    return Request["appSecret"];
                }
            }
    
            private BaseUserInfo _userInfo = null;
            /// <summary>
            /// 获取当前用户
            /// 通过接口AppKey和AppSecret获取的用户
            /// </summary>
            /// <returns></returns>
            public BaseUserInfo UserInfo
            {
                get
                {
                    BaseUserInfo userInfo = null;
                    BaseUserEntity userEntity = BaseUserManager.GetObjectByCodeByCache(AppKey);
                    if (userEntity != null)
                    {
                        if (BaseServicesLicenseManager.CheckServiceByCache(userEntity.Id, AppSecret))
                        {
                            userInfo = new BaseUserInfo();
                            userInfo.Id = userEntity.Id;
                            userInfo.RealName = userEntity.RealName;
                            userInfo.UserName = userEntity.UserName;
                            userInfo.IPAddress = Utilities.GetIPAddress(true);
                        }
                    }
                    return userInfo;
                }
            }
    
            #region 业务库连接
            /// <summary>
            /// 业务库连接
            /// </summary>
            public static IDbHelper BusinessDbHelper
            {
                get
                {
                    return DbHelperFactory.GetHelper(BaseSystemInfo.BusinessDbType, BaseSystemInfo.BusinessDbConnection);
                }
            }
            #endregion
    
            #region 用户中心库连接
            /// <summary>
            /// 用户中心库连接
            /// </summary>
            public static IDbHelper UserCenterDbHelper
            {
                get
                {
                    return DbHelperFactory.GetHelper(BaseSystemInfo.UserCenterDbType, BaseSystemInfo.UserCenterDbConnection);
                }
            }
            #endregion
    
    
        }

    7、统一回传格式实体

        /// <summary>
        /// ApiResultModel
        /// 统一回传格式实体
        /// 
        /// 修改纪录
        /// 
        /// 2016-10-31 版本:1.0 宋彪 创建文件。
        /// 
        /// <author>
        ///     <name>宋彪</name>
        ///     <date>2016-10-31</date>
        /// </author>
        /// </summary>
        public class ApiResultModel
        {
            public HttpStatusCode Status { get; set; }
    
            //public JsonResult<T> Data { get; set; }
           public object Data { get; set; }
            public string ErrorMessage { get; set; }
        }

    8、留言相关接口

        /// <summary>
        /// MessageBookController
        /// 留言相关接口
        /// 
        /// 修改纪录
        /// 
        /// 2016-10-31 版本:1.0 宋彪 创建文件。
        /// 
        /// <author>
        ///     <name>宋彪</name>
        ///     <date>2016-10-31</date>
        /// </author>
        /// </summary>
        [ApiAuthFilter]
        public class CustomerMessageController : ApiController
        {
            /// <summary>
            /// 保存单号留言信息
            /// </summary>
            /// <param name="messageBook"></param>
            /// <returns></returns>
            [HttpPost]
            //[AllowAnonymous] 不需要验证的就加这个标签
            public IHttpActionResult Add([FromBody]MsgbookCusEntity messageBook)
            {
                BaseResult baseResult = new BaseResult();
                if (string.IsNullOrWhiteSpace(messageBook.SystemFrom))
                {
                    baseResult.Status = false;
                    baseResult.StatusMessage = "SystemFrom参数不可为空";
                }
                else
                {
                    try
                    {
                        MsgbookCusManager manager = new MsgbookCusManager(APIOperateContext.BusinessDbHelper, APIOperateContext.Current.UserInfo);
                        MsgbookCusEntity model = new MsgbookCusEntity();
                        model.Id = Guid.NewGuid().ToString("N");
                        model.Message = messageBook.Message;
                        model.SendEmail = messageBook.SendEmail;
                        model.SendTelephone = messageBook.SendTelephone;
                        model.Message = messageBook.Message;
                        model.BillCode = messageBook.BillCode;
                        model.SystemFrom = messageBook.SystemFrom;
                        model.DeletionStateCode = 0;
                        manager.Add(model, false, false);
    
                        baseResult.Status = true;
                        baseResult.StatusMessage = "添加成功。";
                    }
                    catch (Exception ex)
                    {
                        NLogHelper.Warn(ex, "CustomerMessageController AddBillMessage 异常");
                        baseResult.Status = false;
                        baseResult.StatusMessage = "异常:" + ex.Message;
                    }
                }
    
                return Ok(baseResult);
            }
    
            /// <summary>
            /// 获取某个单号的留言
            /// </summary>
            /// <param name="billCode"></param>
            /// <returns></returns>
            [HttpGet]
            public IHttpActionResult GetList(string billCode)
            {
                JsonResult<List<MsgbookCusEntity>> jsonResult = new JsonResult<List<MsgbookCusEntity>>();
                try
                {
                    MsgbookCusManager manager = new MsgbookCusManager(APIOperateContext.BusinessDbHelper, APIOperateContext.Current.UserInfo);
                    List<MsgbookCusEntity> list = new List<MsgbookCusEntity>();
                    list = manager.GetList<MsgbookCusEntity>(new KeyValuePair<string, object>(MsgbookCusEntity.FieldBillCode, billCode)
                    , new KeyValuePair<string, object>(MsgbookCusEntity.FieldDeletionStateCode, 0));
    
                    jsonResult.Status = true;
                    jsonResult.RecordCount = list.Count;
                    jsonResult.Data = list;
                    jsonResult.StatusMessage = "获取成功";
                }
                catch (Exception ex)
                {
                    NLogHelper.Warn(ex, "CustomerMessageController AddBillMessage 异常");
                    jsonResult.Status = false;
                    jsonResult.StatusMessage = "异常:" + ex.Message;
                }
    
                return Ok(jsonResult);
            }
        }

    9、接口调用方法

            /// <summary>
            /// 测试留言接口调用
            /// </summary>
            /// <returns></returns>
            public ActionResult AddCustomerMessage()
            {
                string url = "http://192.168.1.88:808/api/CustomerMessage/Add?";
                WebClient webClient = new WebClient();
                NameValueCollection postValues = new NameValueCollection();
    
                postValues.Add("Message", "填写您的留言内容吧");
                postValues.Add("SendEmail", "youemail@qq.com");
                postValues.Add("SendTelephone", "021-60375335");
                postValues.Add("Code", "661137858");
                postValues.Add("AppKey", "wssavbcn");
                postValues.Add("AppSecret", "350e66b1e6564b0a817163erwwwwe8");
                postValues.Add("SystemFrom", "官网");
    
                byte[] responseArray = webClient.UploadValues(url, postValues);
                string response = Encoding.UTF8.GetString(responseArray);
    
                return Content(response);
            }
  • 相关阅读:
    mysql 定时器
    mysql 存储过程记录
    mysql 常用sql
    mysql 取最后一条数据 分组
    Java8 Stream使用flatMap合并List 交 并 合 差集
    微服务技术栈
    spring boot 拦截 以及Filter和interceptor 、Aspect区别
    在springMVC的controller中获取request,response对象的一个方法
    spring boot 用@CONFIGURATIONPROPERTIES 和 @Configuration两种方法读取配置文件
    SSRS 2016 Forms Authentication
  • 原文地址:https://www.cnblogs.com/hnsongbiao/p/6025677.html
Copyright © 2011-2022 走看看