Comments (16)
@jalchr I wrote my own extension and validation rule to make this happen. Based on the documentation here https://graphql-dotnet.github.io/docs/getting-started/authorization
The usage ends up like this:
graphQLQuery.Field<ResponseGraphType<AccountType>>(
"me",
resolve: context =>
{
// code to resolve here...
}
).RequireRole("admin", "teacher");
The RequireRole can be written as an extension method like this. Which adds the roles comma separated as metadata on the field.
public static void RequireRole(this IProvideMetadata type, params string[] rolesToAdd)
{
var roles = type.GetMetadata<List<string>>("Roles");
if (roles == null)
{
roles = new List<string>();
type.Metadata["Roles"] = roles;
}
roles.Add($"{string.Join(',', rolesToAdd)}");
}
Then we can add our own validation rule like this
public class FieldRoleValidationRule : IValidationRule
{
public INodeVisitor Validate(ValidationContext context)
{
var userContext = context.UserContext as GraphQLUserContext;
var authenticated = userContext.User?.Identity.IsAuthenticated ?? false;
return new EnterLeaveListener(_ =>
{
_.Match<Field>(fieldAst =>
{
var fieldDef = context.TypeInfo.GetFieldDef();
if (fieldDef.RequiresRole() &&
(!authenticated || !fieldDef.UserHasValidRole(userContext.User.Claims)))
{
context.ReportError(new ValidationError(
context.OriginalQuery,
"auth-required",
$"You are not authorized to run this query.",
fieldAst));
}
});
});
}
}
And use dependency injection to add it as an IValidationRule (I'm, using Autofac here).
builder.RegisterType<FieldRoleValidationRule>().As<IValidationRule>().InstancePerDependency();
Now we can create another extension method that validates the roles against the users claims
public static bool UserHasValidRole(this IProvideMetadata type, IEnumerable<Claim> claims)
{
var roles = type.GetMetadata<IEnumerable<string>>("Roles", new List<string>());
// Code to check roles agains claims here
}
from authorization.
I understand. If I were to implement it I would just prefer it to behave like ASP.NET Core does to avoid confusion.
https://stackoverflow.com/a/35610142/279764
from authorization.
Not at present, no. You can have a policy like “TeacherOrAdmin”.
from authorization.
I see that might be a good solution.
Is this a limitation in "AuthorizeWith" ?
Any future plans ?
from authorization.
If I were to add multiple policy support, it would probably function like the .NET Core one does, in an &
comparison. So it would end up as Admin AND Teacher
, which is probably not what you want.
from authorization.
mmm ... I believe it is more like Admin OR Teacher
. The idea is to support multiple policies at same time ... and should not intersect with an AND
from authorization.
If you need differing policies based on role - then MetaData as above is the way to go.
If you just need to give multiple users with different roles access to the same stuff, then
IAuthorizationRequirement or Evaluator works.
from authorization.
Another workaround is to implement custom IAuthorizationEvaluator
:
public class MyAuthorizationEvaluator : IAuthorizationEvaluator
{
private readonly AuthorizationSettings _settings;
public MyAuthorizationEvaluator(AuthorizationSettings settings)
{
_settings = settings;
}
public async Task<AuthorizationResult> Evaluate(
ClaimsPrincipal principal,
object userContext,
Dictionary<string, object> inputVariables,
IEnumerable<string> policies)
{
if (policies == null || !policies.Any())
{
return AuthorizationResult.Success();
}
var context = new AuthorizationContext
{
User = principal ?? new ClaimsPrincipal(new ClaimsIdentity()),
UserContext = userContext
};
return await SatisfiesAtLeastOnePolicyAsync(policies, context) ?
AuthorizationResult.Success() : AuthorizationResult.Fail(context.Errors);
}
private async Task<bool> SatisfiesAtLeastOnePolicyAsync(IEnumerable<string> policies, AuthorizationContext context )
{
var isValid = false;
foreach (var policy in policies)
{
var authorizationPolicy = _settings.GetPolicy(policy);
if (authorizationPolicy == null)
{
context.ReportError($"Required policy '{policy}' is not present.");
break;
}
foreach (var r in authorizationPolicy.Requirements)
{
if (await r.AuthorizeAndVerify(context))
{
isValid = true;
}
}
}
return isValid;
}
}
And an extension for finding errors:
public static class AuthorizationRequirementExtensions
{
public static async Task<bool> AuthorizeAndVerify(this IAuthorizationRequirement requirement, AuthorizationContext context)
{
int originalErrorsCount = context.Errors.Count();
await requirement.Authorize(context);
if (context.Errors.Count() > originalErrorsCount)
{
return false;
}
return true;
}
}
Then register it in the IOC:
services.AddSingleton<IAuthorizationEvaluator, MyAuthorizationEvaluator>();
from authorization.
@Mousavi310 Why do you use break
in your example?
from authorization.
Why do you use break in your example?
Just looks like a stylistic choice - break is going to end the loop and return the initialized value of isValid = false;
.
from authorization.
Taking a second look - in that sample it should really be:
context.ReportError($"Required policy '{policy}' is not present.");
isValid = false;
break;
The way that's written a case like this would not be correct:
- Policy Passes (isValid = true)
- Policy Fails (returns isValid set to true)
from authorization.
Then I don't understand the meaning of the method at all - SatisfiesAtLeastOnePolicyAsync. Why does it break on the first false result?
from authorization.
You read more closely than I did :) - I failed to read the method name "SatisfiesAtLeastOnePolicyAsync".
from authorization.
Exactly. This example is misleading.
from authorization.
Initial problem can be solved by role-based auth - graphql-dotnet/graphql-dotnet#3067 . "Admin" and "Teacher" from initial post look more like roles, not policies. ping @Shane32
from authorization.
Agree @sungam3r . As of GraphQL v5, roles can be applied to the GraphQL schema rather than only policies, which would work in the method requested. (Requires implementation by the authorization rule within this repository, which has not been done here yet.)
I can also explain how authorization works in ASP.Net Core, but I am not sure how it applies to this repository.
Typical ASP.Net Core authorization rules would either apply a single policy ** or ** one or more roles directly. A policy typically contains one or more requirements, one of which could be "is a member of at least one role in the supplied list". However, custom authorization requirements can be written for any desired behavior.
Links:
- https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-6.0
- https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authorization.authorizationpolicybuilder?view=aspnetcore-6.0
- https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authorization.infrastructure.assertionrequirement?view=aspnetcore-6.0
from authorization.
Related Issues (20)
- Checking for a valid JWT and integrating with a Refresh-Token-Workflow HOT 10
- UNAUTHENTICATED error code HOT 3
- In AuthorizationValidationRule.cs the method CheckAuth is called multiple times. Why? HOT 4
- ETA for v4? HOT 18
- IAuthorizationRequirement is not sent the same variable names as those in IResolveField context HOT 2
- ClaimsPrincipal not retrived trying to use AuthorizeWith in GraphQL queries HOT 6
- Any example for schema first auth example? HOT 2
- How to get a status code 401 when not authorized HOT 6
- Move GraphQLAuthExtensions from Harness into new package HOT 6
- Add docs about IAuthorizationSkipCondition and DI
- Method 'ValidateAsync' in type 'GraphQL.Authorization.AuthorizationValidationRule' from assembly 'GraphQL.Authorization, Version=4.0.0.0 HOT 7
- Question: AuthorizeWithPolicy is being ignored HOT 10
- GraphQL .net authorization with JWT token HOT 7
- AddGraphQLAuth no longer works after switching to Middleware HOT 1
- Return 401 and 403 status code HOT 5
- Is this library still relevant with GraphQL 7+ HOT 22
- How to read graphql query from authorization requirement ?
- Graphql Authorization not working HOT 4
- Faulty reference HOT 6
- How to login user and return token and id ? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from authorization.