影片講解
很多時候光靠內建的認證是不夠了,還是需要一情況寫一個符合自己系統的認證機制
這個時候就可以利用AuthorizationFilter來達成
首先先建立一個類別TodoAuthorizationFilter.cs,然後繼承IAuthorizationFilter介面
public class TodoAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
}
}
其中要實作OnAuthorization(),這裡面就是放你要自訂驗證邏輯的地方。
你可以在這裡寫Cookie驗證,不過今天我這邊示範一個簡單的取得token驗證
那token我們都會放在header裡面,欄位會取名為Authorization
所以我們就可以用以下程式碼取得token值
bool tokenFlag = context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues outValue);
這邊是個try方法,結果會是布林,有值就會是true,然後會產生出一個字串
所以我們程式可以這樣寫
if (tokenFlag)
{
if (outValue != "123")
{
}
}
else
{
}
先判斷有沒有取到值,有的話再進行值得驗證,那接著你就會有你的驗證邏輯,不過我這邊就很簡單的寫死有沒有等於123。當沒有等於123就代表驗證失敗,我就要返回失敗訊息,另外沒取到值依樣返回失敗訊息。
那這邊我們可以自訂一個回應格式。
public class 回應格式
{
public dynamic Data { get; set; }
public int HttpCode { get; set; }
public string ErrorMessage { get; set; }
}
這是我個人的習慣,除了可能會返回的data,還會有其他資訊,例如HttpCode和錯誤訊息等等。
所以整個完整的程式碼會是
public class TodoAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var ignore = (from a in context.ActionDescriptor.EndpointMetadata
where a.GetType() == typeof(AllowAnonymousAttribute)
select a).FirstOrDefault();
if (ignore == null)
{
bool tokenFlag = context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues outValue);
if (tokenFlag)
{
if (outValue != "123")
{
context.Result = new JsonResult(new 回應格式()
{
Data = "test1",
HttpCode = 401,
ErrorMessage = "沒有登入"
});
}
}
else
{
context.Result = new JsonResult(new 回應格式()
{
Data = "test2",
HttpCode = 401,
ErrorMessage = "沒有登入"
});
}
}
}
}
這邊只要context.Result被設定值後,程式到這邊就會停止並回傳結果,反之沒設定值就等於通過認證
那我個人在前端會習慣都回200,然後額外再訊息的部分再說明現在是什麼情況或代碼
會這麼做是因為我想要有個區分,區分哪些是我自己判斷的,或程式判斷的
也就是說,我自己判斷的http狀態碼都會是200,其他非200的就是程式內建判斷的
這是我個人習慣啦,如果你堅持狀態碼也要跟著變,你可以下以下指令
context.HttpContext.Response.StatusCode = 401;
那這支如果要下再全域生效的話,同樣是到Startup.cs的ConfigureServices區塊下
services.AddMvc(options =>
{
options.Filters.Add(new TodoAuthorizationFilter());
});
那同樣會跟上一篇cookie會有一樣的問題,就是變成登入api的也會受限制,所以我們才在前面加上一段判斷。
var ignore = (from a in context.ActionDescriptor.EndpointMetadata
where a.GetType() == typeof(AllowAnonymousAttribute)
select a).FirstOrDefault();
這邊我們可以借用內建的AllowAnonymous標籤,只要有加上AllowAnonymous的api我們就略過權限檢查。
另一個簡化寫法
var ignore = context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any();
那我們要如何取得注入的服務呢?很簡單,一樣是利用建構子的方式取得即可。
但如果我們要像這樣[TodoAuthorizationFilter(Role ="333")]
傳值進來
就不能寫建構子,所以我們可以改由以下方式取得服務
TodoContext _todoContext = (TodoContext)context.HttpContext.RequestServices.GetService(typeof(TodoContext));
以上是大致上會用到的程式碼,如果想看更詳細的操作流程可以看影片。
新手分享學習成果,若有錯誤,煩請告知修正,感謝🙏
範例檔:下載