zoukankan      html  css  js  c++  java
  • WebAPI接口安全校验

    通过网上查看相关WebAPI接口验证的方法,整理了一下,直接上代码,功能不复杂,有问题留言,

    //-----------------------------------------------------------------------
    // <copyright file="ApiAuthenticationFilter.cs" company="FenSiShengHuo, Ltd.">
    //     Copyright (c) 2018 , All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------
    
    using System;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Security.Principal;
    using System.Threading;
    using System.Web.Http.Controllers;
    using System.Web.Http.Filters;
    
    namespace DotNet.WeChat.API.Attribute
    {
        using DotNet.Business;
        using DotNet.Model;
        using DotNet.Utilities;
    
        /// <summary>
        /// ApiAuthenticationFilter
        /// 
        /// 2018-07-19 版本:1.0 JiShiYu 创建。    
        ///
        /// <author>
        ///        <name>JiShiYu</name>
        ///        <date>2018-07-19</date>
        /// </author> 
        /// </summary>
        public class ApiAuthenticationFilter : AuthorizationFilterAttribute
        {
            public override void OnAuthorization(HttpActionContext filterContext)
            {
                // 判断是否是不做授权检查的
                var apiNoAuthenticationFilter = filterContext.ActionDescriptor.GetCustomAttributes<ApiNoAuthenticationFilter>();
                if (apiNoAuthenticationFilter != null && apiNoAuthenticationFilter.Any())
                {
                    return;
                }
    
                BaseResult result = null;
                var identity = ParseHeader(filterContext, out result); //取得資料內容
                if (identity == null)
                {
                    ChallengeAuthRequest(filterContext, result); //回傳錯誤訊息
                    return;
                }
                var genericPrincipal = new GenericPrincipal(identity, null);
                //  在认证成功后将认证身份设置给当前线程中Principal属性
                Thread.CurrentPrincipal = genericPrincipal;
                result = OnAuthorizeUser(identity, filterContext);
                if (!result.Status)
                {
                    ChallengeAuthRequest(filterContext, result);
                    return;
                }
            }
    
            /// <summary>
            /// 定义一个方法便校验,并将其修饰为虚方法,以免后续要添加其他有关用户数据
            /// </summary>
            /// <param name="appKey"></param>
            /// <param name="appSecret"></param>
            /// <param name="token"></param>
            /// <param name="actionContext"></param>
            /// <returns></returns>
            protected virtual BaseResult OnAuthorizeUser(BasicAuthenticationIdentity identity, HttpActionContext actionContext)
            {
                BaseResult result = new BaseResult();
                result.Status = false;
                result.StatusCode = Status.ParameterError.ToString();
    
                if (string.IsNullOrWhiteSpace(identity.SystemCode))
                {
                    result.Status = false;
                    result.StatusCode = Status.ParameterError.ToString();
                    result.StatusMessage = "systemCode " + Status.ParameterError.ToDescription();
                    return result;
                }
                // 判断参数
                if (identity.UserInfo != null)
                {
                    // 防止伪造、判断用户的有效性
                    if (!ServiceUtil.VerifySignature(identity.UserInfo))
                    {
                        result.StatusCode = Status.SignatureError.ToString();
                        result.StatusMessage = "userInfo " + Status.SignatureError.ToDescription();
                        return result;
                    }
                    // 这里需要是已经登录的用户,不是已经被踢掉的用户
                    if (!Utilities.ValidateOpenId(identity.UserInfo.Id, identity.UserInfo.OpenId))
                    {
                        result.StatusCode = Status.SignatureError.ToString();
                        result.StatusMessage = "OpenId " + Status.SignatureError.ToDescription();
                        return result;
                    }
                }
                else
                {
                    string ipAddress = Utilities.GetIPAddress(true);
                    // 检查是否为内部ip地址发送出去的手机短信  
                    //if (onlyLocalIp)
                    //{
                    //    if (!IpHelper.IsLocalIp(ipAddress))
                    //    {
                    //        // 不是内网发出的, 也不是信任的ip列表里的,直接给拒绝发送出去
                    //        result.Status = false;
                    //        result.StatusCode = Status.ErrorIPAddress.ToString();
                    //        result.StatusMessage = ipAddress + " " + Status.ErrorIPAddress.ToDescription();
                    //    }
                    //}
    
                    if (string.IsNullOrWhiteSpace(identity.AppKey))
                    {
                        result.StatusCode = Status.ParameterError.ToString();
                        result.StatusMessage = "appKey " + Status.ParameterError.ToDescription();
                        return result;
                    }
                    if (string.IsNullOrWhiteSpace(identity.Signature))
                    {
                        result.StatusCode = Status.ParameterError.ToString();
                        result.StatusMessage = "signature " + Status.ParameterError.ToDescription();
                        return result;
                    }
    
                    if (string.IsNullOrWhiteSpace(identity.TimeSpan))
                    {
                        result.StatusCode = Status.ParameterError.ToString();
                        result.StatusMessage = "TimeSpan " + Status.ParameterError.ToDescription();
                        return result;
                    }
                    else
                    {
                        long unixTimeStamp;
                        if (long.TryParse(identity.TimeSpan, out unixTimeStamp))
                        {
                            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
                            DateTime dtStart = startTime.AddSeconds(unixTimeStamp);
                            TimeSpan ts = DateTime.Now - dtStart;
                            if (ts.TotalMinutes > 5)
                            {
                                result.StatusCode = Status.ParameterError.ToString();
                                result.StatusMessage = "请求时间已过期,请检查请求服务器时间,传递当前时间戳";
                                return result;
                            }
                        }
                        else
                        {
                            result.StatusCode = Status.ParameterError.ToString();
                            result.StatusMessage = "TimeSpan时间戳参数错误,传递当前时间戳";
                            return result;
                        }
                    }
                    //  AppSecret 不应该传
                    //if (string.IsNullOrWhiteSpace(identity.AppSecret))
                    //{
                    //    result.StatusCode = Status.ParameterError.ToString();
                    //    result.StatusMessage = "appSecret " + Status.ParameterError.ToDescription();
                    //    return result;
                    //}
                    // 取服务器上的
                    var secret = BaseServicesLicenseManager.GetSecretByKeyByCache(identity.AppKey);
                    if (string.IsNullOrWhiteSpace(secret))
                    {
                        result.StatusCode = Status.ParameterError.ToString();
                        result.StatusMessage = "找不到appKey的密钥";
                        return result;
                    }
                    else
                    {
                        string serverSignature = System.Web.HttpUtility.UrlEncode(SecretUtilitiesBase.md5(identity.AppKey + identity.TimeSpan + secret));
                        if (!string.Equals(identity.Signature, serverSignature))
                        {
                            result.StatusCode = Status.ParameterError.ToString();
                            result.StatusMessage = "Signature 签名不正确";
                            return result;
                        }
                    }
    
                    result = BaseServicesLicenseManager.CheckService(identity.AppKey, secret, true, false, 0, 0, identity.SystemCode, identity.PermissionCode);
                    if (result.Status)
                    {
                        // 从接口确定当前调用者
                        BaseUserEntity userEntity = BaseUserManager.GetObjectByCodeByCache(identity.AppKey, true);
                        if (userEntity != null)
                        {
                            BaseUserInfo userInfo = new BaseUserInfo();
                            userInfo.Id = userEntity.Id;
                            userInfo.Code = userEntity.Code;
                            userInfo.UserName = userEntity.UserName;
                            userInfo.NickName = userEntity.NickName;
                            userInfo.RealName = userEntity.RealName;
                            userInfo.CompanyId = userEntity.CompanyId;
                            userInfo.CompanyCode = userEntity.CompanyCode;
                            userInfo.CompanyName = userEntity.CompanyName;
                            userInfo.IPAddress = ipAddress;
                            identity.UserInfo = userInfo;
                        }
                    }
                }
    
                return result;
            }
    
            /// <summary>
            /// 解析Headers
            /// </summary>
            /// <param name="filterContext"></param>
            /// <returns></returns>
            protected virtual BasicAuthenticationIdentity ParseHeader(HttpActionContext filterContext, out BaseResult result)
            {
                BasicAuthenticationIdentity authenticationIdentity = null;
                result = new BaseResult();
                BaseUserInfo userInfo = null;
                string systemCode = string.Empty;
                string appKey = string.Empty;
                string timeSpan = string.Empty;
                string signature = string.Empty;
                string permissionCode = string.Empty;
                string userInfoStr = string.Empty;
                try
                {
                    var re = filterContext.Request;
                    var headers = re.Headers;
                    if (headers.Contains("systemCode"))
                    {
                        systemCode = headers.GetValues("systemCode").First();
                    }
                    if (headers.Contains("appKey"))
                    {
                        appKey = headers.GetValues("appKey").First();
                    }
                    if (headers.Contains("timeSpan"))
                    {
                        timeSpan = headers.GetValues("timeSpan").First();
                    }
                    if (headers.Contains("signature"))
                    {
                        signature = headers.GetValues("signature").First();
                    }
                    if (headers.Contains("permissionCode"))
                    {
                        permissionCode = headers.GetValues("permissionCode").First();
                    }
                    if (headers.Contains("userInfoStr"))
                    {
                        userInfoStr = headers.GetValues("userInfoStr").First();
                        userInfo = BaseUserInfo.Deserialize(userInfoStr);
                    }
    
                    authenticationIdentity = new BasicAuthenticationIdentity(systemCode, appKey, timeSpan, signature, userInfo, permissionCode);
                    result.Status = true;
                    result.StatusCode = Status.OK.ToString();
                    result.StatusMessage = "构建成功";
                }
                catch (Exception ex)
                {
                    NLogHelper.Warn(ex, "ParseHeader");
                    result.Status = false;
                    result.StatusCode = Status.Error.ToString();
                    result.StatusMessage = "异常:" + ex.Message;
                }
    
                return authenticationIdentity;
            }
    
            /// <summary>
            /// 授权验证失败
            /// </summary>
            /// <param name="filterContext"></param>
            private static void ChallengeAuthRequest(HttpActionContext filterContext, BaseResult result)
            {
                var dnsHost = filterContext.Request.RequestUri.DnsSafeHost;
                //filterContext.Response = filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                filterContext.Response = filterContext.Request.CreateResponse(HttpStatusCode.OK, result);
                filterContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm="{0}"", dnsHost));
            }
        }
    
        /// <summary>
        /// 认证实体类
        /// </summary>
        public class BasicAuthenticationIdentity : GenericIdentity
        {
            /// <summary>
            /// 系统编号
            /// </summary>
            public string SystemCode { get; set; }
    
            /// <summary>
            /// AppKey
            /// </summary>
            public string AppKey { get; set; }
    
            /// <summary>
            /// 请求时间戳
            /// </summary>
            public string TimeSpan { get; set; }
    
            /// <summary>
            /// Signature 签名值
            /// </summary>
            public string Signature { get; set; }
    
            /// <summary>
            /// 用户信息
            /// </summary>
            public BaseUserInfo UserInfo { get; set; }
    
            /// <summary>
            /// 权限编号
            /// </summary>
            public string PermissionCode { get; set; }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="systemCode"></param>
            /// <param name="appKey"></param>
            /// <param name="timeSpan"></param>
            /// <param name="signature"></param>
            /// <param name="userInfo"></param>
            /// <param name="permissionCode"></param>
            public BasicAuthenticationIdentity(string systemCode, string appKey, string timeSpan, string signature, BaseUserInfo userInfo, string permissionCode)
                : base(appKey, "Basic")
            {
                this.SystemCode = systemCode;
                this.AppKey = appKey;
                this.TimeSpan = timeSpan;
                this.Signature = signature;
                this.UserInfo = userInfo;
                this.PermissionCode = permissionCode;
            }
        }
    }

    不需要做校验的接口,加一个标签

    //-----------------------------------------------------------------------
    // <copyright file="ApiAuthenticationFilter.cs" company="FenSiShengHuo, Ltd.">
    //     Copyright (c) 2018 , All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------
    
    using System.Web.Http.Filters;
    
    namespace DotNet.WeChat.API.Attribute
    {
        /// <summary>
        /// ApiNoAuthenticationFilter
        /// 不做授权检查
        /// 
        /// 2018-07-19 版本:1.0 JiShiYu 创建。    
        ///
        /// <author>
        ///        <name>JiShiYu</name>
        ///        <date>2018-07-19</date>
        /// </author> 
        /// </summary>
        public class ApiNoAuthenticationFilter : AuthorizationFilterAttribute
        { 
        }
    }

    全局校验,放在哪里,你懂的

        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
    
    
    
    
                // 接口授权检查
                config.Filters.Add(new ApiAuthenticationFilter());
    
    
        }
    }
    

      

    测试效果

  • 相关阅读:
    [转] 关于hibernate的缓存使用
    周鸿祎,我的互联网方法论
    cwRsync window下的跨服务器的文件同步
    一个代价11万的bug
    批处理备份
    NodeJs环境部署
    spring接收参数
    @Autowired
    谈谈把网站迁移到阿里云的一些感想和其中遇到的一些问题
    HTML5+JS 《五子飞》游戏实现(一)规则
  • 原文地址:https://www.cnblogs.com/hnsongbiao/p/9381862.html
Copyright © 2011-2022 走看看