Authentication and authorization (three)
前言
在寫三上是在一的基礎上寫的,所以有沒有看過二是沒得關係的,在一中介紹了認證與授權,但是沒有去介紹拿到證書後怎樣去驗證授權。
概念性東西:在這套機制中,把這個許可權認證呢,稱作為policy。這個policy是怎麼樣的過程呢?
就像我前面說的,證書也認證了,policy做的是檢查你的證書中是否符合我心中的標準。
比如說,我有一個介面實行的是駕駛證檢查。結果你只有一張學生證,你不能那一張學生證當駕駛證去開車吧,肯定就不讓你訪問啊。
也許還有點迷糊,請看正文。正文皆為個人理解,如有錯誤,請指正。
正文
請看下面的:
services.AddAuthorization(config=> { var defaultAuthBuilder = new AuthorizationPolicyBuilder(); var defaultPolicy = defaultAuthBuilder.RequireAuthenticatedUser().Build(); config.DefaultPolicy = defaultPolicy; });
這時候就是在配置授權了。
defaultAuthBuilder.RequireAuthenticatedUser().Build() 中,RequireAuthenticatedUser去要求使用者必須經過認證的,也就是不允許匿名使用者,這個很好理解。
設定預設的策略認證就是這個了。
這時候我訪問:
https://localhost:44350/Home/Secret
是正常的,因為我本來就是認證過的。
然後我改了一下:
services.AddAuthorization(config=> { var defaultAuthBuilder = new AuthorizationPolicyBuilder(); var defaultPolicy = defaultAuthBuilder.RequireAuthenticatedUser().RequireClaim(ClaimTypes.Country).Build(); config.DefaultPolicy = defaultPolicy; });
和上面不同的,我加了RequireClaim(ClaimTypes.Country),我要求起碼有一個證書你要有國家。
我再次貼下證書的程式碼,在.net core 認證與授權(一)中也有。
var SchoolClaims = new List<Claim>() { new Claim(ClaimTypes.Name,"Jack"), new Claim(ClaimTypes.Email,"[email protected]") }; var LicensClaims = new List<Claim>() { new Claim(ClaimTypes.Name,"Jack.li"), new Claim(ClaimTypes.Email,"[email protected]"), new Claim("begin","2000.10.1") }; var SchoolIdentity = new ClaimsIdentity(SchoolClaims,"Student Identity"); var CarManagerIdentity = new ClaimsIdentity(LicensClaims, "Licens Identity"); var userPrincipal = new ClaimsPrincipal(new[] { SchoolIdentity, CarManagerIdentity }); HttpContext.SignInAsync("CookieAuth", userPrincipal); return RedirectToAction("Index");
在兩個證書中,都沒得國家。
然後訪問:
https://localhost:44350/Home/Secret
自動跳轉到了一個授權沒有通過的網站,恰巧我沒有寫這個網頁,姑且著就是沒有通過的意思。
然後我再一個證書中添加了一個:
new Claim(ClaimTypes.Country,"china")
這樣我又成功了。
好的,這是預設的策略,那麼如何自定義呢?
config.AddPolicy("Claim.Country", policyBuilder =>
{
policyBuilder.RequireClaim(ClaimTypes.Country);
});
上面我添加了一個策略,名字叫做Claim.Country.
因為不是預設,所以要[Authorize(Policy = "Claim.Country")]
policyBuilder 相當於上面的var defaultAuthBuilder = new AuthorizationPolicyBuilder();。
然後裡面去設定起碼有一個證書中要有國家。
policyBuilder 預設有一些限制可以使用,那麼如何自己來定義呢?究竟是一種什麼模式呢?
public class CustomRequireClaim:IAuthorizationRequirement
{
public CustomRequireClaim(string ClainType)
{
this.ClainType = ClainType;
}
public string ClainType{ get; }
}
public class CustomRequireClaimHandler : AuthorizationHandler<CustomRequireClaim>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequireClaim requirement)
{
var hasClaim = context.User.Claims.Any(u=>u.Type== requirement.ClainType);
if (hasClaim)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
CustomRequireClaim 是什麼呢?繼承IAuthorizationRequirement。其實是模擬生活中的什麼呢,比如說你要向批發商進一匹東西,有一些需求,比如說蘋果要通紅的,你就可以在這裡填寫。
CustomRequireClaimHandler 繼承自AuthorizationHandler,批發商帶一批貨(程式也就是使用者帶著證書來了),你可以這個檢查合格不合格,拿著你的需求表對照。
那麼註冊進入:
config.AddPolicy("Claim.Country", policyBuilder =>
{
policyBuilder.AddRequirements(new CustomRequireClaim(ClaimTypes.Country));
});
同樣需要:
services.AddScoped<IAuthorizationHandler, CustomRequireClaimHandler>();
這裡就有疑問了,你這個policyBuilder.AddRequirements(new CustomRequireClaim(ClaimTypes.Country));就能呼叫到CustomRequireClaimHandler。
這個疑問簡單化就是,你有一個需求,就只調用到檢查類?
其實是在軟體設計中,有這樣一種套路,就是根據實體類,能自動呼叫執行類,這是一種設計模式。其實也能理解,就是呢,比如說公司有一張請假單,都標明是請假單了,肯定交給部門經理啊,AuthorizationHandler
在裡面其實只有IAuthorizationHandler,但是根據CustomRequireClaim能例項出CustomRequireClaimHandler。所以也需要加上:
services.AddScoped<IAuthorizationHandler, CustomRequireClaimHandler>();
同樣,回過頭來,看下面的。
policyBuilder.RequireClaim(ClaimTypes.Country);
如何做到直接點出來,不用這種add的方式呢?也就是說我也想實現這樣的。
policyBuilder.RequireCustomClaim(ClaimTypes.Country);
我要能RequireCustomClaim然後可以呼叫到我給的限制.
下面是使用擴充套件的方式實現:
public static class AuthorizationPolicyBuilderExtensions
{
public static AuthorizationPolicyBuilder RequireCustomClaim(this AuthorizationPolicyBuilder policyBuilder,string claimType)
{
policyBuilder.AddRequirements(new CustomRequireClaim(claimType));
return policyBuilder;
}
}
擴充套件一下AuthorizationPolicyBuilder 就可以,這樣方便複用性。
以前的時候我們這樣寫:
[Authorize(Roles = "admin")]
在這裡就會檢查我們的證書中是否有Roles 為admin。
然後呢,我們同樣可以通過policy去實現。
config.AddPolicy("Claim.Role", policyBuilder =>
{
policyBuilder.RequireClaim(ClaimTypes.Role, "admin");
});
限制需要admin也是可以的,然後[Authorize(Policy= "Claim.Role")]。
具體看自己需求。
總結
後續繼續寫自己對認證授權理解。以上均為個人理解,如有誤差,請指正。