简体   繁体   中英

@PreAuthorize annotation not working spring security

I found many similar questions but none has solved my problem. My problem is ROLE_USER can access functions of ROLE_ADMIN

My spring-security.xml code is following.

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:s="http://www.springframework.org/schema/security"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                    http://www.springframework.org/schema/security
                    http://www.springframework.org/schema/security/spring-security-3.0.xsd">   

<s:http auto-config="true" use-expressions="true">
    <s:intercept-url pattern="/index.jsp" access="permitAll" />
    <s:intercept-url pattern="/welcome*" access="hasRole('ROLE_USER')" />
    <s:intercept-url pattern="/helloadmin*" access="hasRole('ROLE_ADMIN')" />

    <s:form-login login-page="/login" default-target-url="/welcome"
        authentication-failure-url="/loginfailed" />
    <s:logout logout-success-url="/logout" />
</s:http>

<s:authentication-manager>
  <s:authentication-provider>
    <s:user-service>
        <s:user name="asif" password="123456" authorities="ROLE_USER,ROLE_ADMIN" />
        <s:user name="raheel" password="123456" authorities="ROLE_USER" />          
    </s:user-service>
  </s:authentication-provider>
</s:authentication-manager>

when I add <s:global-method-security pre-post-annotations="enabled"/> my code shows resource not found error and when I remove my code execute successfully but ROLE_USER can access ROLE_ADMIN functions

My controller function is.

@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value="/delete", method = RequestMethod.GET)
public String DeleteAll(ModelMap model, Principal principal ) {

    org.springframework.security.core.userdetails.User activeUser = (org.springframework.security.core.userdetails.User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    System.out.println("Active user is "+activeUser.getUsername()+"Authorities are "+activeUser.getAuthorities());
    return "deleteUsers";

}

If you are using XML Configuration don't forget to add the following attribute:

<s:global-method-security pre-post-annotations="enabled"/>

If you are using Java Configuration don't forget to add the following annotation:

@EnableGlobalMethodSecurity(prePostEnabled = true)

You should have

<s:global-method-security pre-post-annotations="enabled"/>

If you want the @PreAuthorize annotations to work.


To answer the comment:

It looks like you're missing the spring-aop dependency.

If you're using maven you need:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${org.springframework.version}</version>
</dependency>

If not you can get the jar from here .

I was facing the same issue. My problem solved when i moved the below element from applicationContext.xml to *-servlet.xml (my dispatcher's configuration xml).

<security:global-method-security secured-annotations="enabled"/>

You have to include this element on your dispatcher's xml NOT on your application's xml .
Spring FAQ

I had the same issue working with annotations, the problem was that there was no @Controller annotation in my controller.


So it seems you need :

  • These annotations in your Spring Security configuration :

     @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) 
  • Theses annotations in your controller :

     @Controller public class ServiceRS { @RequestMapping(value = "/admin", method = RequestMethod.GET) @PreAuthorize("hasAuthority('ROLE_ADMIN')") public void wsAdmin() { [...] } } 

Plus if you are still having issues, consider adding this to your log4j2 configuration :

    <Logger name="org.springframework.security" level="trace" additivity="false">
        <AppenderRef ref="Console" />
        <AppenderRef ref="RollingRandomAccessFile" />
    </Logger>

You will see in logs if your annotations are considered by Spring :

TRACE org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource {} [main] Looking for Pre/Post annotations for method 'wsAdmin' on target class '***.ServiceRS' 
DEBUG org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource {} [main] @org.springframework.security.access.prepost.PreAuthorize(value=hasAuthority('ROLE_ADMIN')) found on specific method: public void ***.ServiceRS.wsAdmin() 
DEBUG org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource {} [main] Caching method [CacheKey[***.ServiceRS; public void ***.ServiceRS.wsAdmin()]] with attributes [[authorize: 'hasAuthority('ROLE_ADMIN')', filter: 'null', filterTarget: 'null']] 

And obviously you can consider adding breakpoints in corresponding methods in org.springframework.security.access.expression.SecurityExpressionRoot to see if a call is done with the condition in your annotation.

Regards.

Try with @Secured annotation,

Then you'll have

@Secured("ROLE_ADMIN")
@RequestMapping(value="/delete", method = RequestMethod.GET)
public String DeleteAll(ModelMap model, Principal principal ) {

  ...

}

Here's a detailed blog post about it .

This might help you :

<security:global-method-security secured-annotations="enabled" proxy-target-class="true"/>

Regards.

None of the above answers have worked for me. I had to go the route of adding security decorators.

Decorators are placed on beans within file servlet-context.xml .

First add security schema to the XML namespace:

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
...
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

Then apply the decorator to the implementation of the service bean, like so..

<beans:bean id="myService" class="my.service.impl.MyServiceImpl" scope="request">
    <security:intercept-methods>
        <security:protect access="ROLE_USER" method="get*"/>
        <security:protect access="ROLE_ADMIN" method="set*"/>
    </security:intercept-methods>
</beans:bean>

This issue will arise when using Servlet 3 with Web Async Support. Spring Security 3.1.4 and below lose their security context once enterting the anonymous method of the Callable method.

Upgrading Spring Security to 3.2.0 RC1 will solve your problems.

Maven dependency:

<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.2.0.RC1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>3.2.0.RC1</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>http://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>http://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

put below tag in another spring configuration file, not in spring security configuration file.

I was also getting the same error.

<security:global-method-security secured-annotations="enabled" proxy-target-class="true"/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM