Reputation: 53
I am trying to learn how a microservices approach with net core should be. So after a lot of tutorials this is what I have got so far:
I have created two apis projects: Company and Package. Ports 5002 and 5010
I need a gateway, Ocelot is the one. I have this configuration:
{
"Routes": [
// Company Api
{
"DownstreamPathTemplate": "/api/company/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/api/company/{everything}",
"UpstreamHttpMethod": [
"GET"
],
"AuthenticationOptions": {
"AuthenticationProviderKey": "TestKey",
"AllowedScopes": []
},
"AddHeadersToRequest": {
"CustomerId": "Claims[sub] > value"
}
},
// Anonymous Company Api
{
"DownstreamPathTemplate": "/api/company/getHomeSections",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/api/anonymous/company/getHomeSections",
"UpstreamHttpMethod": [
"GET"
]
},
// Package Api
{
"DownstreamPathTemplate": "/api/package/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5010
}
],
"UpstreamPathTemplate": "/api/package/{everything}",
"UpstreamHttpMethod": [
"GET"
],
"AuthenticationOptions": {
"AuthenticationProviderKey": "TestKey",
"AllowedScopes": []
}
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost:5000"
},
"AllowedHosts": "*"
}
I have configured a client in angular 10. I can log in, I get the token and everything works as expected.
Now my big question is, how do I grant access to users on a API / Role basis? So lets say Role A has access to company/read and Role B to company/read and company/write?
How do actually achieve that?
Thanks a lot.
Upvotes: 1
Views: 2339
Reputation: 31760
how do I grant access to users on a API / Role basis?
There are two ways:
On the client
This method doesn't involve the gateway at all, just IdentityServer.
If you just want role-based behaviour in the UX - to allow/disallow certain calls or to hide/show certain screens/components, you can do the following:
In the gateway/on the back-end
This is more complicated, but if you want to have role-based behaviour in your back-end then you will need to code for it in your services. One way of doing this is to have each service accept a collection of roles as a header parameter, for example. Then you can:
However, this feels clumsy. Thinking about access control at the service-level, roles feel a bit too coarse-grained.
Maybe a third way...
So, role-based behaviour works well on your front-end, but what about your back-end?
Since you are already taking advantage of the ability to inject the CustomerId user claim into the downstream service, we should consider another solution.
Rather than role based behaviour on your back-end, why not just use the resource identifier to control access? For example, a private http operation to do with a customer can be defined with the customerId as part of the path:
GET /customers/{customerId}
In Ocelot, the upstream path can be exposed as
GET /customers
The customerId claim is injected into the downstream path when the request is received on the gateway (note: Ocelot does not support path parameter injection out-of-the-box. You need to create a class derived from DelegatingHandler, and use it with the DelegatingHandlers[]
collection in the ocelot.json to do this).
In a similar vein, you can secure your company API by creating an Ocelot route from GET /company
to GET /company/{companyId}
where companyId is a user claim.
Combined with role-based behaviour on your front-end, this approach gives you much finer-grained access control on your gateway/back-end than you can get with role-based behaviour. You get the best of both worlds.
Upvotes: 2