2013-03-12 14 views
11

Dodaję Spring Security do jednego projektu Spring. Architektura systemu to REST, a użytkownik ma dostęp do różnych zasobów.@PreAuthorize nie działa z regułami bezpieczeństwa metody i parametrami metody

Chciałbym udostępnić dane osobowe administratorom i użytkownikom będącym właścicielami tych informacji. zacząłem prosta: filtrowanie profilu użytkownika takiego:

W moim warstwy chciałem użyć metody adnotacje i zawierać parametry metody usługi ..

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

Ale to nie działa w ogóle. Każdy użytkownik może zobaczyć wszystkie profile (administratorów i wszystkich użytkowników, również), gdy ten adres URL jest wymagany (Web warstwa):

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

Oto moja 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 sprawdziłem Spring Security 3.1 book i widocznie moja konfiguracja jest taka, jak sugeruje książka. Czytałem inne posty Stack Overflow (here i here), ale nie miałem szczęścia.

Aktualizacja: Dodany 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" /> 

Aktualizacja: Dodałem spring-security-aspects do POM i bez zmian. Inne zmiany sugerowane w odpowiedziach zostały przetestowane, ale adnotacje takie jak @PreAuthorize nadal nie działają. CNA to problem między kontekstami? Czy powodem może być użycie aspektu?

Co robię źle?

+0

Twoja metoda "Usuario getUser (int id)" jest zdefiniowana w niektórych interfejsach? Domyślnie tego rodzaju adnotacje mogą nie działać (proxy JDK są używane do dodawania sprawdzeń autoryzacji w środowisku wykonawczym i mogą być kierowane tylko na metody interfejsu). –

+0

@MaksymDemidas Nie. Mój UsuarioService implementuje UserDetailsService. Pracuję również z własną klasą UsuarioDetails, która rozszerza moją domenę Usuario i implementuje UserDetails – Spacemonkey

+0

wft man? :) zmień" "/ */*/*/*/*" "na "/ **" – Yura

Odpowiedz

9

W końcu znalazłem rozwiązanie. W TAK Znalazłem kilka przydatnych odpowiedzi. Zobacz here i here.

Przeprowadziłem global-method-security do application-context.xml, co jest kontekstem moich usług.

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

Gdzie mode="aspectj" jak Javadoc mówi:

... mogą być używane do określenia, że ​​AspectJ powinien być stosowany zamiast domyślnej wiosennym AOP. Jeśli zostanie to ustawione, zabezpieczone klasy muszą zostać splecione z AnnotationSecurityAspect z modułu aspektów bezpieczeństwa wiosennego.

Oczywiście, dodałem do POM spring-security-aspects:

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

Cieszę się, że znalazłeś rozwiązanie! –

+0

Drogi @MaksymDemidas, dziękuję za pomoc. – Spacemonkey

+0

move global-method-security rozwiązało mój problem. http://docs.spring.io/spring-security/site/faq/faq.html#faq-method-security-in-web-context – user227353

0

Dodaj nowy interfejs:

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

wdrożyć go w usłudze użytkownika i spróbuj ponownie. Spring będzie w stanie dodać wymagane kontrole autoryzacji za pomocą serwerów proxy JDK.

Jako inną opcję można skonfigurować Spring do użycia większej ilości bibliotek o dużej wadze, takich jak Javassist lub nawet AspectJ. W tym przypadku interfejs nie będzie potrzebny.

EDYCJA. Upewnij się, że global-method-security jest zadeklarowany w tym samym kontekście sprężystym z komponentem obsługi użytkownika.

+0

Nie działa podczas dodawania interfejsu. Czy powinienem opisywać metodę tak jak w moim poście, a nie w interfejsie, czy nie? – Spacemonkey

+0

Tak, adnotacje są zwykle stosowane po stronie implementacji –

+1

Pokaż swój plik źródłowy xml. Możesz mieć dwa konteksty sprężyn (dla fasoli i Spring MVC). Czy jesteś pewien, że twoja cecha zabezpieczeń globalnych jest zdefiniowana w tym samym kontekście, co twoja usługa użytkownika? –

0

alternatywny sposób, aby to działało jest dodanie następujący kod w swoim security.xml

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

Będzie upewnij się, że tylko administrator może uzyskać dostęp do zasobów zaczynając od wzorca/użytkownika /.

Powiązane problemy