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>
Używam wersji Spring Security 3.0.5. Dodałem @ExceptionHandler (AccessDeniedException.class) do mojego kontrolera. Nadal otrzymuję tę samą stronę logowania. –
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? –
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