[.NET MVC] 自訂驗證 實作紀錄

1.需透過一個Code,UserID 到SQL 內做條件的篩選 取得該UserID 是否符合Code的權限範圍

2.所以多設置了一個 AppAuthorizeAttribute  功能 程式碼如下

程式碼說明:

簡單說就是透過Controller 戴帽子方式蓋上去

因為繼承了AuthorizeAttribute,我們改寫原本OnAuthorization 的method

判斷如果有AppFunctionId 這個attribute 就走新的驗證,如果沒有就走原本AuthorizeAttribute 的驗證

接下來我們自訂的AuthorizeCore 也只是再進去SQL裡面SELECT 而已了

完整原始碼

using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;

namespace IPMS.Filter
{
    #region Dependency

    using Service.Common;
    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using static IPMS.EnumSet;

    #endregion

    /// <summary>
    /// 功能權限驗證機制
    /// </summary>
    public class AppAuthorizeAttribute : AuthorizeAttribute
    {
        #region Declare

        /// <summary>
        /// 功能代號
        /// </summary>
        public string AppFunctionId { get; set; }

        /// <summary>
        /// service instance
        /// </summary>
        private readonly AuthorizeService authorizeService;

        #endregion

        #region Constructor

        public AppAuthorizeAttribute()
        {
            authorizeService = new AuthorizeService();
        }

        #endregion

        #region 授權驗證 - OnAuthorization()

        /// <summary>
        /// 授權驗證
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            //對有進網域的電腦而言不太可能發生
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            //檢查是否有輸入AppFunctionId
            if (string.IsNullOrEmpty(AppFunctionId))
            {
                //沒輸入走原本Authorize機制
                base.OnAuthorization(filterContext);
            }
            else
            {
                if (!AuthorizeCore(filterContext.HttpContext))
                {   
                    // 驗證失敗,導至授權失敗頁,but..彈跳視窗無法跳轉!
                    filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary
                        {
                            { "controller", "Authorize" },
                            { "action", "Failed" }
                        }
                    );
                }

                //驗證有過也不留cache
                SetCachePolicy(filterContext);
            }
        }

        #endregion

        private void SetCachePolicy(AuthorizationContext filterContext)
        {
            //怕下一秒把這個人被改成Unauth,但因為上一秒他成功進來過,被瀏覽器cache permission,導致雖然已unauth卻還是進的來,所以set 0
            var cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null);
        }

        private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            if (!Enum.IsDefined(typeof(HttpValidationStatus), validationStatus))
            {
                throw new InvalidEnumArgumentException(nameof(validationStatus), (int) validationStatus,
                    typeof(HttpValidationStatus));
            }

            validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
        }

        #region 覆寫AuthorizeAttribute類別的AuthorizeCore方法 - AuthorizeCore()

        /// <summary>
        /// 覆寫AuthorizeAttribute類別的AuthorizeCore方法
        /// </summary>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            string userRole = IdentityStore.Read().UseRole;
            if (!httpContext.User.Identity.IsAuthenticated)
            {
                return false;
            }
            //角色一 Plan相關程式 直接給權限
            var rd = httpContext.Request.RequestContext.RouteData;
            string currentController = rd.GetRequiredString("controller").ToLower();
            if (currentController == "plan" && userRole == nameof(RoleCode.Unit1_Checker_Rol))
            {
                return true;
            }

            //判斷此角色是否有功能權限
            if (!authorizeService.GetAuthorization(userRole, AppFunctionId, AppFunctionName))
            {
                LogSet.LogError(
                    $@"Invoke GetAuthorization() error. 
                              Input: [roleId={userRole}], 
                                     [funcId={AppFunctionId}], 
                                     [funcName={AppFunctionName}]
                              Path: [url={((HttpRequestWrapper)((HttpContextWrapper)httpContext).Request).Path}]");

                return false;
            }

            return true;
        }

        #endregion
    }
}