.NET Core 2.0 API:
首先,我尝试使用IAuthorizationPolicyProvider
来制定动态策略:
public class MyAuthorizationPolicyProvider: IAuthorizationPolicyProvider
{
internal const string PolicyPrefix = "MyJwt";
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if(!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
return Task.FromResult<AuthorizationPolicy>((AuthorizationPolicy)null);
var authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
authorizationPolicyBuilder.AddRequirements((IAuthorizationRequirement)new MyAuthorizationRequirement(policyName.Substring(PolicyPrefix.Length)));
return Task.FromResult<AuthorizationPolicy>(authorizationPolicyBuilder.Build());
}
}
public class MyAuthorizationHandler: AuthorizationHandler<MyAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyAuthorizationRequirement requirement)
{
if(!context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
if(SomeLibrary.IsContextValid(context, requirement))
context.Succeed((IAuthorizationRequirement)requirement);
else
context.Fail();
return Task.CompletedTask;
}
}
并添加身份验证:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
});
services.AddSingleton<IAuthorizationHandler, MyAuthorizationHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, MyAuthorizationPolicyProvider>();
“我的授权”属性:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
internal const string PolicyPrefix = "MyJwt";
public MyAuthorizeAttribute(string permission)
{
this.Permission = permission;
}
public string Permission
{
get
{
if(this.Policy.Length < PolicyPrefix.Length)
return (string)null;
return this.Policy.Substring(PolicyPrefix.Length);
}
set
{
this.Policy = PolicyPrefix + value;
}
}
}
我曾经用过:[MyAuthorize("anythings")]
到目前为止,一切都很好。现在,我需要添加一个新的身份验证(我的意思是两个都可以一起工作)。
因此,我更改了MyAuthorizationPolicyProvider
以支持新政策:
public class MyAuthorizationPolicyProvider: IAuthorizationPolicyProvider
{
internal const string PolicyPrefix = "MyJwt";
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if(policyName == "newpolicy") //here
return AddNewPolicy();
if(!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
return Task.FromResult<AuthorizationPolicy>((AuthorizationPolicy)null);
var authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
authorizationPolicyBuilder.AddRequirements((IAuthorizationRequirement)new MyAuthorizationRequirement(policyName.Substring(PolicyPrefix.Length)));
return Task.FromResult<AuthorizationPolicy>(authorizationPolicyBuilder.Build());
}
}
并更改添加身份验证:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
})
.AddJwtBearer("newSchema", options =>
{
options.TokenValidationParameters = GetNewSchemaTokenValidationParameters();
});
services.AddSingleton<IAuthorizationHandler, MyAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, MyNewAuthorizationHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, MyAuthorizationPolicyProvider>();
MyNewAuthorizationHandler
是:
public class MyNewAuthorizationHandler: AuthorizationHandler<MyNewAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyNewAuthorizationRequirement requirement)
{
if(!context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
if(SomeNewLibrary.IsContextValid(context, requirement))
context.Succeed((IAuthorizationRequirement)requirement);
else
context.Fail();
return Task.CompletedTask;
}
}
我使用[Authorize(Policy = "newpolicy")]
现在,第一个身份验证可与MyAuthorizationHandler
一起正常工作,但第二个身份验证在MyNewAuthorizationHandler
中失败,因为未对用户进行身份验证并且此行返回失败:if(!context.User.Identity.IsAuthenticated)
我错过了什么?
如何进行多重身份验证,同时使用IAuthorizationPolicyProvider
动态添加策略?
我知道是否将AddAuthentication更改为:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "newSchema"; //here
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
})
.AddJwtBearer("newSchema", options =>
{
options.TokenValidationParameters = GetNewSchemaTokenValidationParameters();
});
然后第二个工作正常,第一个失败,如何验证两个模式?
答案 0 :(得分:0)
经过一番搜索,我找到了multiple-authorization-policy-providers。
首先更改MyAuthorizationPolicyProvider
以支持所有其他策略:
public class MyAuthorizationPolicyProvider: IAuthorizationPolicyProvider
{
private readonly DefaultAuthorizationPolicyProvider _fallbackPolicyProvider;
internal const string PolicyPrefix = "MyJwt";
public MyAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options)
{
_fallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if(!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
return _fallbackPolicyProvider.GetPolicyAsync(policyName); //here return back to static policies
var authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
authorizationPolicyBuilder.AddRequirements((IAuthorizationRequirement)new MyAuthorizationRequirement(policyName.Substring(PolicyPrefix.Length)));
return Task.FromResult<AuthorizationPolicy>(authorizationPolicyBuilder.Build());
}
}
然后修改添加身份验证的方式:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
})
.AddJwtBearer("newSchema", options =>
{
options.TokenValidationParameters = GetNewSchemaTokenValidationParameters();
});
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("newSchema") //add new schemas here
.Build();
//here: add static policies as much as you want
options.AddPolicy("newpolicy", new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("newSchema")
.AddRequirements(new MyNewAuthorizationRequirement("newpolicy"))
.Build());
});
services.AddSingleton<IAuthorizationHandler, MyAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, MyNewAuthorizationHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, MyAuthorizationPolicyProvider>();