问题
I'm trying to use the "LocalApi" feature of IdentityServer4 with some custom Policies.
I have an API (hosted on the same application instance as IdentityServer4) that is divided into three parts (Server, Manager, Product) and for three clients (Server, Manager, Product). Client can only call the devoted part of the API and I would do this with Policies based on scopes.
So I have the following:
Starup:
services.AddLocalApiAuthentication(); // Add API hosted on same application than IdentityServer
services.AddAuthorization(options =>
{
options.AddPolicy("Manager", policy =>
{
//policy.RequireClaim("scope", configuration.GetValue<string>("EchinoLoginApiManagerScopeOptions:Name"));
policy.RequireClaim("scope", "local_api_manager_scope");
policy.RequireClaim("scope", IdentityServerConstants.LocalApi.ScopeName);
});
options.AddPolicy("Server", policy =>
{
//policy.RequireClaim("scope", configuration.GetValue<string>("EchinoLoginApiServerScopeOptions:Name"));
policy.RequireClaim("scope", "local_api_server_scope");
policy.RequireClaim("scope", IdentityServerConstants.LocalApi.ScopeName);
});
options.AddPolicy("Product", policy =>
{
//policy.RequireClaim("scope", configuration.GetValue<string>("EchinoLoginApiProductScopeOptions:Name"));
policy.RequireClaim("scope", "local_api_product_scope");
policy.RequireClaim("scope", IdentityServerConstants.LocalApi.ScopeName);
});
});
And my ApiResource
new ApiResource
{
Name = IdentityServerConstants.LocalApi.ScopeName,
Scopes =
{
new Scope()
{
Name = IdentityServerConstants.LocalApi.ScopeName,
DisplayName = IdentityServerConstants.LocalApi.ScopeName,
},
new Scope()
{
Name = "local_api_product_scope",
DisplayName = echinoLoginApiProductScopeOptions.DisplayName,
UserClaims = echinoLoginApiProductScopeOptions.UserClaims
},
new Scope()
{
Name = "local_api_manager_scope",
DisplayName = echinoLoginApiManagerScopeOptions.DisplayName,
UserClaims = echinoLoginApiManagerScopeOptions.UserClaims
},
new Scope()
{
Name = "local_api_server_scope",
DisplayName = echinoLoginApiServerScopeOptions.DisplayName,
UserClaims = echinoLoginApiServerScopeOptions.UserClaims
}
}
}
And finally my server client
new Client
{
ClientId = echinoServerOptions.Id,
ClientName = echinoServerOptions.Name,
ClientSecrets =
{
new Secret(echinoServerOptions.Secret.Sha256())
},
AllowedGrantTypes = GrantTypes.ClientCredentials,
//AllowedScopes = AddLocalApiScope(echinoServerOptions.AllowedScopes)
AllowedScopes = { "IdentityServerApi", "server_scope", "local_api_server_scope" }
},
So in my controller I use [Authorize(Policy = "Server")] but I always have an authentication failed. If I use [Authorize(LocalApi.PolicyName)] it's working but then I don't have my custom policy.
The payload of the JWT token is the following:
{
"nbf": 1582632694,
"exp": 1582636294,
"iss": "https://localhost:44334",
"aud": [
"IdentityServerApi",
"EchinoLoginApi"
],
"client_id": "EchinoServer",
"scope": [
"IdentityServerApi",
"local_api_server_scope",
"server_scope"
]
}
I must be missing something but I can't found what.
Can anybody give me a hand?
回答1:
For local apis, you should use [Authorize(LocalApi.PolicyName)] with your custom policy together.
[Authorize("productpolicy")]
[Authorize(LocalApi.PolicyName)]
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{...
Or you can handle it in another way:
options.AddPolicy(ClientLocalScopes.AuthenticationAuthorization, policy =>
{
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
policy.RequireAuthenticatedUser();
// write your code here
});
来源:https://stackoverflow.com/questions/60394565/identityserver4-localapi-with-custom-policy-in-net-core-3-1