Return JSON on unauthorized REST service request using Spring Security 'hasPermission()'

10,073

What is happening is an AccessDeniedException is being thrown, so you want to configure your system to intercept that exception and instead return JSON.

You can set up an @ExceptionHandler method within your controller which catches the AccessDeniedException. However, you probably want to do the same thing in all your controllers, so if you are using Spring 3.2, you can use @ControllerAdvice annotation on a separate 'advice' class and then include the @ExceptionHandler method in there.

@ControllerAdvice 
public class ExceptionControllerAdvice {

    @ExceptionHandler(AccessDeniedException.class)
    @ResponseBody
    public String exception(AccessDeniedException e) {
        return "{\"status\":\"access denied\"}";
    } 
}
Share:
10,073
Yadu Krishnan
Author by

Yadu Krishnan

I am a Java and Scala enthusiast. Interested in learning new things.

Updated on June 20, 2022

Comments

  • Yadu Krishnan
    Yadu Krishnan almost 2 years

    I am implementing method level restriction/authorization (on REST services) using Spring security.
    I have used the spring expression language and implemented custom Expression Evaluator.

    It is working fine for me. However, if an unauthorized user tries to access the service, it is responding with a login page. Since my application is REST based only, I want to return only JSON data for all the requests.

    How do I make it return JSON instead of the login page?(eg: {status : Denied})

    Here is the code Snippet:

    CustomEvaluator

    public boolean hasPermission(Authentication authentication, Object userId, Object permissionId) {
            List<String> permList = new MyDAO().getPermissionsForUser((String) userId);
            if(permList.contains(((String) permissionId))){
                return true;
            }else{
                return false;
            }
        }
    

    Service

    @PreAuthorize("hasPermission(#userId, '3')")
        public String testAuthorization(Object obj, String userId){
    
            System.out.println("Has access to the service method....");
    
            return  "success";
        }
    

    Controller

    public @ResponseBody String testAuthorization(Object o,@RequestParam("userId") String userId){
            System.out.println("User ID = "+userId);
            String abc = service.testAuthorization(o,userId);
            return "{\"status\":\"success\"}";
        }
    

    spring-security.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:security="http://www.springframework.org/schema/security"
           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">
    
    
        <security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled">
            <security:expression-handler ref="expressionHandler"/>
        </security:global-method-security>
    
        <!-- This is where we configure Spring-Security  -->
        <security:http auto-config="true" use-expressions="true" access-denied-page="/auth/auth/denied" >
            <security:intercept-url pattern="/auth/auth/login" access="permitAll"/>
            <security:intercept-url pattern="/auth/main/admin" access="hasRole('ROLE_ADMIN')"/>
            <security:intercept-url pattern="/auth/main/common" access="hasRole('ROLE_USER')"/>
    
    
        </security:http>
    
        <security:authentication-manager>
            <security:authentication-provider user-service-ref="customUserDetailsService">
                <security:password-encoder ref="passwordEncoder"/>
            </security:authentication-provider>
        </security:authentication-manager>
    
        <!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
        <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
    
        <!-- A custom service where Spring will retrieve users and their corresponding access levels  -->
        <bean id="customUserDetailsService" class="com.cjl.security.service.CustomUserDetailsService"/>
    
        <bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
            <property name="permissionEvaluator" ref="permissionEvaluator"/>
        </bean>
    
        <bean id="permissionEvaluator" class="com.cjl.security.evaluators.MethodPermissionEvaluator"/>
    
    
    </beans>