Can Spring Security use @PreAuthorize on Spring controllers methods?

JavaSpring MvcControllerSpring Security

Java Problem Overview


Can Spring Security use @PreAuthorize on Spring controllers methods?

Java Solutions


Solution 1 - Java

Yes, it works fine.

You need <security:global-method-security pre-post-annotations="enabled" /> in ...-servlet.xml. It also requires CGLIB proxies, so either your controllers shouldn't have interfaces, or you should use proxy-target-class = true.

Solution 2 - Java

See Spring Security FAQ (emphasis mine).

> In a Spring web application, the application context which holds the > Spring MVC beans for the dispatcher servlet is often separate from the > main application context. It is often defined in a file called > myapp-servlet.xml, where “myapp” is the name assigned to the Spring > DispatcherServlet in web.xml. An application can have multiple > DispatcherServlets, each with its own isolated application context. > The beans in these “child” contexts are not visible to the rest of the > application. The “parent” application context is loaded by the > ContextLoaderListener you define in your web.xml and is visible to all > the child contexts. This parent context is usually where you define > your security configuration, including the > element). As a result any security constraints applied to methods in > these web beans will not be enforced, since the beans cannot be seen > from the DispatcherServlet context. You need to either move the > declaration to the web context or moved the > beans you want secured into the main application context. > > Generally we would recommend applying method security at the service > layer rather than on individual web controllers.

If you apply pointcuts to service layer you only need to set <global-method-security> in your app's security context.

Solution 3 - Java

If you're using Spring 3.1, you can do some pretty cool stuff with this. Take a look at https://github.com/mohchi/spring-security-request-mapping. It's a sample project that integrates @PreAuthorize with Spring MVC's RequestMappingHandlerMapping so that you can do something like:

@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
    return "authenticatedHomePage";
}

@RequestMapping("/")
public String homePage() {
    return "homePage";
}

A request for "/" will call authenticatedHomePage() if the user is authenticated. Otherwise it will call homePage().

Solution 4 - Java

It's over two years since this question was asked but because of problems I had today I'd rather discourage using @Secured, @PreAuthorize, etc. on @Controllers.

What didn't work for me was @Validated combined with @Secured controller:

@Controller
@Secured("ROLE_ADMIN")
public class AdministrationController {

// @InitBinder here...

@RequestMapping(value = "/administration/add-product", method = RequestMethod.POST)
public String addProductPost(@ModelAttribute("product") @Validated ProductDto product, BindingResult bindingResult) {
    // ...
}

Validator simply does not fire (Spring MVC 4.1.2, Spring Security 3.2.5) and no checks are performed.

Similar problems are caused by CGLIB proxies used by Spring (when there is no interface implemented by a class, Spring creates CGLIB proxy; if the class implements any interface then JDK Proxy is generated - documentation, well explained here and here).

As mentioned in the answers that I linked above, is't better to use Spring Security annotations on service layer that usually implements interfaces (so JDK Proxies are used) as this does not lead to such problems.

If you want to secure web controllers, the better idea is to use <http> and <intercept-url /> that are bound to specific urls rather than methods in controllers and work pretty well. In my case:

<http use-expressions="true" disable-url-rewriting="true">

    ...

    <intercept-url pattern="/administration/**" access="hasRole('ROLE_ADMIN')" />

</http>

Solution 5 - Java

There is already a reply regarding how to make it work by changing xml configuration; however, if you are working with code-based configuration, you can achieve the same by placing the following annotation over your @Configuration class:

@EnableGlobalMethodSecurity(prePostEnabled=true)

Solution 6 - Java

To Extend the answer provided by Andy, you can use:

@PreAuthorize("hasRole('foo')")

to check the specific role.

Solution 7 - Java

step1: add @EnableGlobalMethodSecurity(prePostEnabled = true) annotation in SecurityConfig class . like this:

 @Configuration
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
   .....
 }

step 2: you can add @PreAuthorize() annotation in controller or service or repository layer. in a method or class level. for example:

@RestController
@PreAuthorize("isAuthenticated()")    
public class WebController {  
  
    @PreAuthorize("permitAll()")  
    @GetMapping("/")  
    public String home() {  
        return "Welcome home!";  
    }

    @GetMapping("/restricted")   
    public String restricted() {  
        return "restricted method";  
    }
}

or

@RestController    
public class AdminController {
   
   
   @PreAuthorize("hasRole('ADMIN')")
   @GetMapping("/admin")
   public String adminMethod() {
   }
}

Solution 8 - Java

First you need to add this annotation in your WebSecurityConfig to enable @Pre and @Post annotations.

    @EnableGlobalMethodSecurity(prePostEnabled = true)

You can also check roles/authorities as follows

    @PreAuthorize("hasAuthority('ROLE_ADMIN')")

equivalent to

    @PreAuthorize("hasRole('ROLE_ADMIN')")

You can also check multiple roles/authorities as follows

    @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionegervariView Question on Stackoverflow
Solution 1 - JavaaxtavtView Answer on Stackoverflow
Solution 2 - JavaTomaszView Answer on Stackoverflow
Solution 3 - JavaandyView Answer on Stackoverflow
Solution 4 - JavadominikView Answer on Stackoverflow
Solution 5 - JavaOlgaMaciaszekView Answer on Stackoverflow
Solution 6 - JavaAtulView Answer on Stackoverflow
Solution 7 - Javaehsan maddahiView Answer on Stackoverflow
Solution 8 - JavaSiddhey SankheView Answer on Stackoverflow