我沒有使用個人資訊。
我有這樣的ASP.NET Core配置,啟用了兩種認證方案,cookie和basic auth:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "_auth";
options.Cookie.HttpOnly = true;
options.LoginPath = new PathString("/Account/Login");
options.LogoutPath = new PathString("/Account/LogOff");
options.AccessDeniedPath = new PathString("/Account/Login");
options.ExpireTimeSpan = TimeSpan.FromHours(4);
options.SlidingExpiration = true;
})
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null)。
BasicAuthenticationHandler是一個繼承自AuthenticationHandler并覆寫HandleAuthenticateAsync的自定義類,用于檢查基本認證挑戰的請求頭,并回傳AuthenticateResult.Fail()或AuthenticateResult.Success()與一張票和用戶宣告。
它的作業原理是:
- 帶有
[Authorize]標簽的控制器/操作將檢查cookie并重定向到不存在的登錄頁面。 - 帶有
[Authorize(AuthenticationSchemes = "BasicAuthentication")]標簽的控制器/動作將檢查頭資訊,如果不存在,則回復401 Unauthorized HTTP代碼。 - 帶有
[Authorize(AuthenticationSchemes = "BasicAuthentication,Cookies")]標簽的控制器/操作將允許兩種方法訪問該頁面,但在兩種檢查都失敗時,會以某種方式使用Cookies重定向機制。
我的目標是讓我的大部分專案使用Cookies(因此它被設定為默認),但有一些API型別的控制器接受這兩種方法。此外,還應該可以對控制器/操作進行標記,以便在需要時回傳特定的Json主體(與登錄重定向或基本的401回應相反),但只針對某些控制器。
在過去的兩天里,我一直在StackOverflow上閱讀不同的類似問題和答案,但似乎沒有什么能滿足我的需求。
以下是我找到的一些方法:
AddCookie下的選項允許你設定某些事件,如OnRedirectToAccessDenied,并從那里改變回應。這并不可行,因為它適用于整個專案。- 在我的
BasicAuthenticationHandler類下,AuthenticationHandler類允許覆寫HandleChallengeAsync以改變那里的回應而不是回復401。不幸的是,它同樣適用于你使用該方案的所有地方,而不是在控制器/行動層面。我不確定它是否適用于混合多個方案的情況。 - 許多答案都指向在解決方案中添加一個中間件,同樣,它影響了整個專案。
- 許多答案指出了策略,但它似乎是為了控制用戶是否可以根據要求訪問資源,而不是控制他不訪問資源時的回應。
- 許多答案建議創建一個繼承自
AuthorizeAttribute、IAuthorizationFilter的類。同樣,這允許覆寫OnAuthorization方法來決定用戶是否有權訪問資源,但不能控制正常認證方案失敗后的回應。
我在想,要么我漏掉了一個過濾器型別,要么我需要創建一個第三種認證型別,它將混合前兩種認證并控制回應。如果能找到一種方法,在選項中添加一個自定義的錯誤資訊,那也是很好的。
uj5u.com熱心網友回復:
我在評論中打了這個字......但它不適合......所以這里是我們在選擇解決方案之前可能需要明確的東西:
- 授權程序發生在控制器上方的中間件 。
是的,AuthorizationMiddleware是在我們使用app.UseAuthorization();時注冊的,它遠在控制器層之上,所以它在請求到達控制器之前很久就被回傳了,所以,任何型別的過濾器都不能在這里應用。
- 不指定一個認證方案或策略將很容易導致不穩定的行為。
想象一下,認證程序回傳一個User的實體,它與請求保持一致,但是如果cookie和basicAuth的權限不同,比如cookie有myclaim,而basicAuth沒有,會發生什么?兩種方案的相關程序是不同的(比如對cookie的挑戰會導致/Account/Login和basicAuth導致/Login?還有各種邏輯情況,我們可以在每個頁面上實作。
我知道,這是不可能的,但這將成為一個混亂,不是對這些代碼的作者,而是對那些維護者來說。
我知道這不可能,但這將變得一團糟,不是對這些代碼的作者,而是對那些維護者。
這聽起來可能很詳細,但如果之后有更多的認證需求出現(如Jwt),它將很快成為負擔。在客戶端上涵蓋每一種情況將使用戶體驗變得相當尷尬(比如,半認證和授權)。
。如果在專案中不可避免的話。我建議用ForwardDefaultSelector創建一個默認的認證方案,它將為每個請求選擇使用哪種認證方案。并保持一個穩定的路由HashSet,它將用于檢測在哪個端點上設定Json Response,以滿足比AuthorizationMiddleware更高層次的愿望,當然是通過使用中間件。然后,我們將范圍縮小到兩個集中的地方來檢查授權。
當我們試圖讓一個東西做一些事情的時候,混亂出現了。至少在這種情況下,我認為我們在除錯階段會更容易呼吸。
uj5u.com熱心網友回復:
我設法通過IAuthorizationMiddlewareResultHandler來實作。這不是我最喜歡的方法,因為每個專案只能有一個,而且它攔截了所有的呼叫,但是通過檢查一個特定的(空)屬性是否被設定,我可以控制流程:
公共類<
public class JsonAuthorizationAttribute : Attribute
{
public string Message { get; set; }
}
public class MyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler DefaultHandler = new AuthorizationMiddlewareResultHandler()。
public async Task HandleAsync(RequestDelegate requestDelegate, HttpContext httpContext, AuthorizationPolicy authorizationPolicy, PolicyAuthorizationResult policyAuthorizationResult)
{
// 如果授權被禁止且資源有特定的屬性,則以json方式回應
如果(policyAuthorizationResult.Forbidden).
{
var endpoint = httpContext.GetEndpoint();
var jsonHeader = endpoint?.Metadata?.GetMetadata<JsonAuthorizationAttribute>()。
如果(jsonHeader != null)
{
var message = "Invalid User Credentials";
如果(!string.IsNullOrEmpty(jsonHeader.Message))
message = jsonHeader.Message;
httpContext.Response.StatusCode = 401;
httpContext.Response.ContentType = "application/json"。
var jsonResponse = JsonSerializer.Serialize(new
{
error = message
});
await httpContext.Response.WriteAsync(jsonResponse);
回傳。
}
}
// 回歸到默認實作。
await DefaultHandler.HandleAsync(requestDelegate, httpContext, authorizationPolicy, policyAuthorizationResult)。
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/311774.html
標籤:
