@QueryMapping or @PreAuthorize don't work when used on an @GraphQlRepository
Setup
Given
- a Spring-Boot artifact (Spring-Boot version 2.7.4)
- with JPA based DBMS (PostgreSQL) Repo
- using lombok
- a working Spring Security OAuth2.0+JWT setup (with a working role mapper)
Entity like:
// package + imports ...
@Entity
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
@ToString
public class Foo {
@Id
@GenericGenerator(name = "UUIDGenerator", strategy = "uuid2")
@GeneratedValue(generator = "UUIDGenerator")
@Column(name = "id", updatable = false, nullable = false)
public UUID id;
private String name;
}
GraphQlRepository like:
// package + imports ...
@GraphQlRepository
public interface FooGraphQlRepository extends JpaRepository<Foo, UUID>, QuerydslPredicateExecutor<Foo> {
@PreAuthorize("hasRole('ROLE_read')")
@QueryMapping(name = "findFooByName")
List<Foo> findFooByName(@Argument("name") String name);
@PreAuthorize("hasRole('ROLE_read')")
@QueryMapping
List<Foo> findAll();
@PreAuthorize("hasRole('ROLE_read) and hasRole('ROLE_write')")
@MutationMapping(name = "createFoo")
Foo save(@Argument("input") FooInput fooInput);
// I did use also the Foo Entity but it did not change anything.
@ProjectedPayload
public interface FooInput {
String getName();
}
}
schema.graphqls like:
type Query {
foo: [Foo]
findFooByName(name: String): [Foo]
}
type Mutation {
createFoo(input: FooInput): Foo
}
input FooInput {
name: String!
}
type Foo {
id: ID!
name: String!
}
Issue
In the end it never mattered what I used in the @QueryMapping, @MutationMappin or even @PreAuthorize config.
The requests have always been forwarded to a responding method in the repository.
Neither using an non-existant role (like "ROLE_doesnotexists") or changing the name in either the mutation or query mapper changed anything. Removing the @GraphQlRepository made the repo unreachable (just to make sure, there wasn't any other bean responding).
Workaround
Using a dedicated @Controller with a separate CrudRepository
CrudRepository like:
// package + imports ...
public interface Foo extends CrudRepository<Foo, UUID> {
List<Foo> findFooByName(@Param("name") String name);
}
Controller like:
// package + imports ...
@Controller
@SchemaMapping(typeName = "Foo")
public class FooGraphQlController {
@Autowired
private FooRepository fooRepository;
@PreAuthorize("hasRole('ROLE_read')")
@QueryMapping("findFooByName")
public List<Foo> findFooByName(@Argument("name") String name) {
return fooRestRepository.findFooByName(name);
}
@PreAuthorize("hasRole('ROLE_read')")
@QueryMapping("foo")
Iterable<Foo> findAll() {
return fooRestRepository.findAll();
}
@PreAuthorize("hasRole('ROLE_read') and hasRole('ROLE_write')")
@MutationMapping(name = "createFoo")
Foo createFoo(@Argument("input") FooInput fooInput) {
return fooRestRepository.save(fooInput.builder()
.name(Foo.getName())
.build());
}
@ProjectedPayload
public interface FooInput {
String getName();
}
}
The Controller approach works but adds quite some boilerplate code.
Did I miss something?
I would expect this to work. Maybe the repository is not decorated with a Spring Security AOP proxy? You can check by putting a breakpoint in QuerydslDataFetcher#autoRegistrationConfigurer and inspecting the repositories passed in. Otherwise, if you could please extract a small sample, and we'll have a closer look and debug it.
I just noticed this. I was only referring to @PreAuthorize in my previous comment, but I see you also have @QueryMapping and @MutationMapping on the repository, which is not expected to work. Those are only for use in controllers.
Are you aware that @GraphQlRepository makes the repository eligible for auto-registration for queries that match the return type, so it shouldn't be necessary to put @QueryMapping. We don't, however, support auto-registration for mutations currently, but it's something we could explore. It's analogous to queries, but matching by the input rather than the return type.
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.