1. 程式人生 > >WebAPI接口安全校驗

WebAPI接口安全校驗

nic apps 驗證 時區 image 用戶數據 unix ger nlog

通過網上查看相關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());


    }
}

  

測試效果

技術分享圖片

WebAPI接口安全校驗