ASP.NET Core Integration
If you are using ASP.NET Core, you can use our integration NuGet package called PolicyServer.Runtime.Client.AspNetCore.
This sets up the runtime client and integrates it with various ASP.NET Core facilities. Use the DI approach:
services.AddPolicyServerRuntimeClient(Configuration.GetSection("PolicyServerRuntimeClient"));
You can then use dependency injection in e.g. controllers to evaluate policies:
public class HomeController : Controller
{
private readonly IPolicyServerRuntimeClient _client;
public HomeController(IPolicyServerRuntimeClient client)
{
_client = client;
}
public async Task<IActionResult> Secure()
{
var result = await _client.EvaluateAsync(User);
return View(result);
}
}
Dealing with outgoing HTTP Connections
The runtime client makes several outgoing HTTP calls (e.g. for acquiring access tokens and evaluating policies). Every outgoing HTTP call is made using an HTTP client that got created by the ASP.NET Core HttpClientFactory.
This allows for centralized configuration and lifetime management and additional featurers like correlation ID propagation (using the X-Correlation-ID
header).
You can also futher customize the HTTP clients used by the runtime library, e.g. adding retry logic via the Polly library:
services.AddPolicyServerRuntimeHttpClient()
.AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
}));
services.AddPolicyServerRuntimeTokenHttpClient()
.AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
}));
Note
Internally the runtime library uses two clients - one for requesting access tokens, and one for evaluating policies. They can be customized independently.
Configuring a Proxy
If any of the back-channel clients need to use a proxy, you can configure them e.g. using the following sample snippet:
var handler = new HttpClientHandler
{
UseProxy = true,
Proxy = new WebProxy("https://proxy")
};
services.AddPolicyServerRuntimeHttpClient()
.ConfigurePrimaryHttpMessageHandler(s => handler);
Passing Route or QueryString Parameters
It is possible that the name of the policy that should be evaluated is dynamic based on parameters to your application.
For example, for this action method:
[HttpGet("Operate/{customer}"))]
public IActionResult Operate(string customer, string hospitalId)
{
...
}
The policy that should be evaluated is "/Hospitals/{customer}/{hospitalId}"
, where the route or query string parameters are dynamically substituted into the policy path.
Dynamically constructing the path can always be done imperatively, but it might be desirable to use the declarative [Authorize]
syntax instead.
PolicyServer’s [Authorize]
attribute support allows using a special syntax for the name passed to the [Authorize]
attribute such that route and query string parameter values will be automatically passed as the path to the policy to be evaluated.
The syntax is in the form "PermissionName:{ParamName}/{OtherParamName}"
.
Note the :
character separates the permission name from the policy path.
The {name}
placeholders indicate route or query string parameter values to substitute into the policy path.
For example:
[HttpGet("Operate/{customer}"))]
[Authorize("PerformSurgery:{customer}/{hospitalId}")]
public IActionResult Operate(string customer, string hospitalId)
{
...
}
For the request /Operate/CustomerA?hospitalId=5
, the [Authorize]
attribute will evaluate the CustomerA/5
policy and require a require a PerformSurgery
permission in the results.
Note
Don’t forget that the base policy name from the configuration file will be prepended to the path of the policy when using the [Authorize]
attribute in the above examples.
Integration with Legacy Code
If you have existing investments in the standard .NET claims API or role-based authorization, you can turn PolicyServer roles and permissions into claims automatically. This will make them compatible with the standard .NET APIs.
By adding the following service to your ASP.NET Core application, the current user will get evaluated automatically against the base policy on every request.
The outcome will be transformed into claims of type role
and permission
and added as a separate identity tot the current user principal:
public void ConfigureServices(IServiceCollection services)
{
services.AddPolicyServerClaimsTransformation();
}
This allows you e.g. to write the following code:
// if you are using the UsePolicyServerClaimsTransformation middleware, roles are mapped to claims
// this allows using the classic authorize attribute
[Authorize(Roles = "nurse")]
public async Task<IActionResult> NursesOnly()
{
// can also use the standard .NET APIs
var permissions = User.FindAll("permission");
var isNurse = User.HasClaim("role", "nurse");
return View("success");
}