iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
自我挑戰組

Bug仔的筆記本系列 第 28

訂製你的權限驗證 Authorize Filter

  • 分享至 

  • xImage
  •  

這是前一陣子在改善未登入者的跳轉方式的衍生問題。之前的方法都是考慮沒有登入的使用者,要前往不同身分才能瀏覽的頁面時分別導向不同的登入畫面。

今天的體驗則是再加強一下。如果你已經登入了,要前往不同身分才能使用的頁面。是不是也要重新登入?

我們之前做的是 Authentication 身分驗證,就像是大門的警衛,有員工證的人才能進公司。

當你有了員工證,進了公司後,你想要進董事長辦公室。能進不能進,就看你有沒有權限,這就是Authorization授權驗證。

在 ASP.NET MVC 裡面可以使用 AuthorizeAttribute 來做不同身分的授權驗證。

使用的方式很簡單。

[Authorize(Roles = "teacher")]
public IActionResult Index()
{
...

在 MVC 的生命週期中,會先經過AuthenticationFilter(身分驗證)->AuthorizeFilter(授權驗證)->ActionFilter

但如果你的權限規則不一樣?判斷邏輯很特殊?那你可以自己實作一個過濾器AuthorizeFilter來處理權限判斷。管理權限的就是AuthorizeAttribute。所以實作最簡單的方式就是繼承AuthorizeAttribute後,覆寫他。

在 MVC 的生命週期中,會先經過AuthenticationFilter(身分驗證)->AuthorizeFilter(授權驗證)->ActionFilter

繼承 AuthorizeAttribute 並覆寫

最簡單的方式就是繼承AuthorizeAttribute後,覆寫裡面負責權限判斷的AuthorizeCore()就可以了。

public class TeatherAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User as ClaimsPrincipal;
        // 是不是老師
        return user.HasClaim("MyRole", "老師");
    }
}

AuthorizeCore只是負責判斷 True 或 False 而已。

可以看一下AuthorizeAttributeOnAuthorization()內容,以下是程式碼原始的內容。

/// <summary>在處理序要求授權時呼叫。</summary>
/// <param name="filterContext">篩選條件內容,這個內容封裝 <seecref="T:System.Web.Mvc.AuthorizeAttribute" /> 的使用資訊。</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="filterContext" /> 參數是 null。</exception>
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
  if (filterContext == null)
    throw new ArgumentNullException(nameof (filterContext));
  if (OutputCacheAttribute.IsChildActionCacheActive((ControllerContext) filterContext))
    throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
  if ((filterContext.ActionDescriptor.IsDefined(typeof (AllowAnonymousAttribute), true) ? 1 : (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof (AllowAnonymousAttribute), true) ? 1 : 0)) != 0)
    return;
  if (this.AuthorizeCore(filterContext.HttpContext))
  {
    HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
    cache.SetProxyMaxAge(new TimeSpan(0L));
    cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidateHandler), (object) null);
  }
  else
    this.HandleUnauthorizedRequest(filterContext);
}

可以看到OnAuthorization(),會判斷AllowAnonymousAttribute後,才會執行AuthorizeCore()拿到驗證結果,如果驗證不通過,會去執行HandleUnauthorizedRequest(),所以我們接下來就覆寫 HandleUnauthorizedRequest(),來達到我們跳轉的需求

覆寫 HandleUnauthorizedRequest()

HandleUnauthorizedRequest原始的程式碼如下:

/// <summary>處理授權失敗的 HTTP 要求。</summary>
    /// <param name="filterContext">封裝 <see cref="T:System.Web.Mvc.AuthorizeAttribute" /> 的使用資訊。<paramref name="filterContext" /> 物件,這個物件包含控制器、HTTP 內容、要求內容、動作結果和路由資料。</param>
    protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext) => filterContext.Result = (ActionResult) new HttpUnauthorizedResult();

我簡單改寫後如下

public class TeatherAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User as ClaimsPrincipal;
        // 是不是老師
        return user.HasClaim("MyRole", "老師");
    }
    
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
           filterContext.Controller.TempData["ErrorMsg"] = "Fail|訪問此頁面需要老師權限,請重新登入!";
            filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary(
                    new { action = "login", controller = "Teather"  }));
        }
}


上一篇
使用 ClosedXML 對 Excel 做處理
下一篇
基於 Task 的非同步
系列文
Bug仔的筆記本30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言