Search code examples
javaspringspring-bootspring-security

@PreAuthorize(hasRole(...)) vs requestMatchers(...).hasRole(...)


What is the difference between using @PreAuthorize(hasRole(...)) and using requestMatchers(...).hasRole(...)? Does it have any impact on security? And what is better to use?

I've seen that both solutions are used, so I don't know which one is better.

    @GetMapping("/companies")
    @PreAuthorize("hasAnyRole('USER','ADMIN')")
    public ResponseEntity<CompanyDto> getCompanyById(@PathVariable("companyId") Long companyId) {

        CompanyDto companyDto = companyService.getCompanyById(companyId);

        return new ResponseEntity<>(companyDto, HttpStatus.OK);
    }

or

SecurityConfig

.requestMatchers(HttpMethod.GET, "/companies").hasAnyAuthority(ADMIN, USER)

Solution

  • @PreAuthorize is a method-level security annotation as defined in the respective documentation:

    Annotation for specifying a method access-control expression which will be evaluated to decide whether a method invocation is allowed or not.

    On the other hand, using the requestMatchers is done in the HTTP security configurations (as shown in the securityFilterChain example)! In general, it matches the incoming requests based on specific patterns or alike, for example the security constraint of the request having a role - thus requestMatchers().hasRole() is evaluated at the time of the HTTP request, before the controller method is even invoked!

    • For more complex authorization use cases that involve method parameters/you need to check values before the method is invoked in itself, the @PreAuthorize is better.
    • For simpler cases in which you only need to secure some URL endpoints based on roles (and there is no requirement to consider method parameters in security checks) requestMatchers().hasRole() is easier.

    Most often than not, a combination of both of them is useful. For example, a requestMatcher to secure general endpoints and then @PreAuthorize for more complex checks.