2013-03-12 21 views
11

Aggiungo Spring Security a un progetto Spring. L'architettura del sistema è REST e l'utente può accedere a diverse risorse.@PreAuthorize non funziona con le regole di sicurezza del metodo e i parametri del metodo

Vorrei consentire l'accesso alle informazioni personali agli amministratori e agli utenti proprietari di tali informazioni. Ho iniziato semplice: il filtraggio profilo utente in questo modo:

Nel mio livello di servizio ho voluto usare metodo annotazioni e comprendono parametri di metodo ..

@PreAuthorize("hasRole('ROLE_ADMIN') or principal.userId == #id") 
public Usuario getUser(int id) throws DAOException { 
    ... 
} 

Ma questo non funziona affatto. Ogni utente può vedere tutti i profili (amministratori e tutti gli utenti anche) quando viene richiesto questo URL (Web strato):

@RequestMapping(value="/user/{uid}", method=RequestMethod.GET) 
    public ModelAndView getUser(@PathVariable int uid) throws DAOException { 
     userDAO = new UsuarioJPADAO(); 
     userService.setUsuarioDAO(userDAO); 

    return new ModelAndView("user", "user", userService.getUser(uid)); 
} 

Ecco il mio security.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans:beans xmlns="http://www.springframework.org/schema/security" 
     xmlns:beans="http://www.springframework.org/schema/beans" 
     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.1.xsd 
     http://www.springframework.org/schema/security 
     http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 

<!-- Security Annotations --> 
    <global-method-security 
     pre-post-annotations="enabled"/> 

<http auto-config="true" use-expressions="true"> 
    <intercept-url pattern="/css/**" access="permitAll" /> 
    <intercept-url pattern="/images/**" access="permitAll" /> 
    <intercept-url pattern="/js/**" access="permitAll" /> 
    <intercept-url pattern="/favicon.ico" access="permitAll" /> 
    <intercept-url pattern="/login" access="permitAll" /> 

    <intercept-url pattern="/users" access="hasRole('ROLE_ADMIN')" /> 
    <intercept-url pattern="https://stackoverflow.com/users/page/*" access="hasRole('ROLE_ADMIN')" /> 
    <intercept-url pattern="/customers" access="hasRole('ROLE_ADMIN')" /> 
    <intercept-url pattern="/employees" access="hasRole('ROLE_ADMIN')" /> 

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

    <intercept-url pattern="/*" access="hasAnyRole('ROLE_ADMIN, ROLE_EMPLOYEE, ROLE_PARTNER, ROLE_USER')" /> 
    <intercept-url pattern="/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" /> 
    <intercept-url pattern="/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" /> 
    <intercept-url pattern="/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" /> 
    <intercept-url pattern="/*/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" /> 
    <intercept-url pattern="/*/*/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" /> 
    <intercept-url pattern="/*/*/*/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" /> 
    <form-login login-page="/login" login-processing-url="/doLogin" 
       authentication-failure-url="/login?error" 
       username-parameter="username" password-parameter="password" 
       default-target-url="/default" /> 

    <logout invalidate-session="true" logout-success-url="/login?logout" logout-url="/logout"/> 
</http> 
<authentication-manager> 
    <authentication-provider user-service-ref="UsuarioService"> 
    </authentication-provider> 
</authentication-manager>  

I ho controllato Spring Security 3.1 book e apparentemente la mia configurazione è come suggerisce il libro. Ho letto altri messaggi Stack Overflow (here e here) ma non ho avuto fortuna.

Aggiornamento: Aggiunto application-context.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:p="http://www.springframework.org/schema/p"  
     xmlns:aop="http://www.springframework.org/schema/aop" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xmlns:mvc="http://www.springframework.org/schema/mvc" 
     xmlns:security="http://www.springframework.org/schema/security" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:jee="http://www.springframework.org/schema/jee" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
     http://www.springframework.org/schema/mvc 
     http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.1.xsd 
     http://www.springframework.org/schema/security 
     http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 

    <context:annotation-config /> 

<context:component-scan base-package="com.pe.fs" /> 

<mvc:annotation-driven /> 

<mvc:resources mapping="/**" location="/" /> 

<mvc:interceptors> 
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> 
    <property name="paramName" value="lang" /> 
</bean> 
</mvc:interceptors> 

<!-- DataSource --> 
<bean id="jpaDataSource" class="oracle.jdbc.pool.OracleDataSource" 
    destroy-method="close" 
    p:driverType="oracle.jdbc.OracleDriver" 
    p:user="**********" 
    p:password="**********" 
    p:uRL="jdbc:oracle:thin:@localhost:1521:XE" 
/> 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property> 
    <property name="persistenceUnitName" value="freesunPU" /> 
    <property name="dataSource" ref="jpaDataSource" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> 
      <property name="showSql" value="false" /> 
     </bean> 
    </property> 
    <property name="loadTimeWeaver"> 
     <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> 
    </property> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 
    p:entityManagerFactory-ref="entityManagerFactory" /> 

<tx:annotation-driven mode="aspectj"/> 

<context:load-time-weaver aspectj-weaving="autodetect" /> 

Update: ho aggiunto spring-security-aspects di POM e nessun cambiamento. Altre modifiche suggerite nelle risposte sono state testate con ma annotazioni come @PreAuthorize non funzionano ancora. Cna questo è un problema tra contesti? Può essere l'uso dell'aspettoJ il motivo?

Cosa sto sbagliando?

+0

Il metodo 'Usuario getUser (int id)' è definito in alcune interfacce? Per impostazione predefinita questo tipo di annotazioni potrebbe non funzionare (i proxi di JDK sono utilizzati per aggiungere controlli di autorizzazione in runtime e possono scegliere solo i metodi di interfaccia) –

+0

@MaksymDemidas No. My UsuarioService implementa UserDetailsService. Sto anche lavorando con la mia classe UsuarioDetails che estende il mio dominio Usuario e implementa UserDetails – Spacemonkey

+0

wft man? :) modifica ""/*/*/*/*/* "" per "/ **" – Yura

risposta

9

Finalmente ho trovato la soluzione. In SO ho trovato alcune risposte utili. Vedi here e here.

Ho spostato global-method-security su application-context.xml quale è il contesto dei miei servizi.

<security:global-method-security 
    mode="aspectj" 
    secured-annotations="enabled" 
    jsr250-annotations="disabled" 
    pre-post-annotations="enabled"/> 

Dove mode="aspectj" come Javadoc dice:

... può essere utilizzato per specificare che AspectJ dovrebbe essere usato al posto del AOP primavera default. Se impostato, le classi protette devono essere tessute con lo AnnotationSecurityAspect dal modulo degli aspetti di sicurezza di primavera.

Naturalmente, ho aggiunto al POM spring-security-aspects:

<dependency> 
    <groupId>org.springframework.security</groupId> 
    <artifactId>spring-security-aspects</artifactId> 
    <version>3.1.3.RELEASE</version> 
</dependency> 
+0

felice di vedere che hai trovato la soluzione! –

+0

Gentile @MaksymDemidas, grazie per il tuo aiuto. – Spacemonkey

+0

move global-method-security ha risolto il mio problema. http://docs.spring.io/spring-security/site/faq/faq.html#faq-method-security-in-web-context – user227353

0

Aggiungi nuova interfaccia:

public interface UserService extends UserDetailsService { 
    Usuario getUser(int id) throws DAOException 
} 

recepirlo nel vostro servizio utente e riprova. Spring sarà in grado di aggiungere i controlli di autorizzazione richiesti usando i proxy JDK.

Come un'altra opzione è possibile configurare Spring per utilizzare alcune librerie più pesanti come Javassist o AspectJ. In questo caso l'interfaccia non sarà necessaria.

MODIFICA. Assicurarsi che global-method-security sia dichiarato nello stesso contesto di primavera con il bean del servizio utente.

+0

Non funziona quando si aggiunge l'interfaccia. Devo annotare il metodo come ho fatto nel mio post, non nell'interfaccia, no? – Spacemonkey

+0

Sì, le annotazioni normalmente vengono applicate sul lato dell'implementazione –

+1

Si prega di mostrare il vostro xml primavera. Puoi avere due contesti primaverili (per fagioli e per Spring MVC). Sei sicuro che il tuo elemnt di sicurezza del metodo globale sia definito nello stesso contesto con il tuo servizio utente? –

0

Il modo alternativo per farlo funzionare è quello di aggiungere il seguente codice nel tuo security.xml

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

Sarà assicurati che solo l'amministratore possa accedere alle risorse che iniziano con pattern/user /.

Problemi correlati