2014-05-09 7 views
5

Wdrażam ograniczenia poziomu metod/autoryzację (na usług REST) przy użyciu zabezpieczeń Spring.
Użyłem języka wyrażeń wiosennych i zaimplementowałem własny Wyrażenie Wyrażeń.Zwróć JSON na nieautoryzowane żądanie usługi REST za pomocą Spring Security 'hasPermission()'

To działa dobrze dla mnie. Jeśli jednak nieautoryzowany użytkownik spróbuje uzyskać dostęp do usługi, odpowiada na stronie logowania. Ponieważ moja aplikacja to opierająca się tylko na REST, chcę zwrócić tylko dane JSON dla wszystkich żądań.

Jak mogę zrobić to powrócić JSON zamiast strony logowania (np {status : Denied})?

Oto kod fragment:

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; 
     } 
    } 

usługi

@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\"}"; 
    } 

wiosna-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> 

Odpowiedz

5

Co się dzieje jest AccessDeniedException jest wyrzucane, więc chcesz skonfigurować system, aby przechwycić ten wyjątek i zamiast zwrotu JSON.

Możesz ustawić metodę @ExceptionHandler w swoim kontrolerze, która przechwyci AccessDeniedException. Jednak prawdopodobnie chcesz zrobić to samo we wszystkich kontrolerach, więc jeśli używasz Spring 3.2, możesz użyć adnotacji @ControllerAdvice w oddzielnej klasie "porady", a następnie dołączyć tam metodę @ExceptionHandler.

@ControllerAdvice 
public class ExceptionControllerAdvice { 

    @ExceptionHandler(AccessDeniedException.class) 
    @ResponseBody 
    public String exception(AccessDeniedException e) { 
     return "{\"status\":\"access denied\"}"; 
    } 
} 
+0

Używam wersji Spring Security 3.0.5. Dodałem @ExceptionHandler (AccessDeniedException.class) do mojego kontrolera. Nadal otrzymuję tę samą stronę logowania. –

+0

Przepraszam, mój błąd. Już działa. W wersji 3.0.5, jeśli muszę obsługiwać ten sam wyjątek w innym kontrolerze, w jaki sposób? Powielanie obsługi wyjątków jest jedynym sposobem? –

+0

Możesz albo zduplikować program obsługi, albo możesz utworzyć element abstractController, który będzie rozszerzany przez wszystkie inne kontrolery. Możliwe, że będziesz w stanie stworzyć aspekt itd, który deklaruje obsługę wszystkich kontrolerów, chociaż przyznaję, że go nie wypróbowałem. – DavidA

Powiązane problemy