2013-03-12 21 views
11

Tôi đang thêm Bảo mật mùa xuân vào một dự án Spring. Kiến trúc của hệ thống là REST và người dùng có thể truy cập vào các tài nguyên khác nhau.@PreAuthorize không hoạt động với các quy tắc bảo mật phương pháp và thông số phương pháp

Tôi muốn cấp quyền truy cập vào thông tin cá nhân cho quản trị viên và người dùng là chủ sở hữu của thông tin này. Tôi đã bắt đầu đơn giản: lọc lý lịch thành viên như thế này:

Trong lớp dịch vụ của tôi tôi muốn sử dụng phương pháp chú thích và bao gồm các thông số phương pháp ..

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

Nhưng điều này không làm việc ở tất cả. Bất kỳ người dùng có thể xem tất cả hồ sơ (quản trị viên và tất cả người dùng cũng có) khi URL này được yêu cầu (lớp Web):

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

Đây là tôi 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>  

tôi đã kiểm tra Spring Security 3.1 book và cấu hình của tôi dường như là cuốn sách gợi ý. Tôi đã đọc các bài đăng Chồng tràn khác (herehere) nhưng tôi không có may mắn.

Cập nhật: Added 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" /> 

Cập nhật: Tôi đã thêm spring-security-aspects để POM và không có thay đổi. Các thay đổi khác được đề xuất trong các câu trả lời đã được kiểm tra nhưng các chú thích như vậy @PreAuthorize vẫn không hoạt động. Cna đây là một vấn đề giữa các bối cảnh? Có thể là việc sử dụng của aspectJ lý do?

Tôi đang làm gì sai?

+0

Phương thức 'Usuario getUser (int id)' được định nghĩa trong một số giao diện? Theo mặc định, loại chú thích này có thể không hoạt động (JDK proxieas được sử dụng để thêm kiểm tra ủy quyền trong thời gian chạy và chúng chỉ có thể nhắm mục tiêu các phương thức giao diện) –

+0

@MaksymDemidas No. My UsuarioService triển khai UserDetailsService. Tôi cũng đang làm việc với lớp UsuarioDetails của riêng tôi mở rộng Usuario miền của tôi và triển khai UserDetails – Spacemonkey

+0

wft man? :) thay đổi ""/*/*/*/*/* "" thành "/ **" – Yura

Trả lời

9

Cuối cùng tôi đã tìm được giải pháp. Trong SO tôi tìm thấy một số câu trả lời hữu ích. Xem herehere.

Tôi đã di chuyển global-method-security đến application-context.xml đó là ngữ cảnh của các dịch vụ của tôi.

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

đâu mode="aspectj" như Javadoc nói:

... có thể được sử dụng để xác định rằng AspectJ nên được sử dụng thay cho AOP Xuân mặc định. Nếu được đặt, các lớp bảo mật phải được dệt bằng AnnotationSecurityAspect từ mô-đun về khía cạnh bảo mật mùa xuân.

Tất nhiên, tôi đã thêm vào POM spring-security-aspects:

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

vui mừng khi thấy rằng bạn đã tìm thấy giải pháp! –

+0

Kính gửi @MaksymDemidas, cảm ơn sự giúp đỡ của bạn. – Spacemonkey

+0

di chuyển toàn cầu-phương pháp bảo mật giải quyết vấn đề của tôi. http://docs.spring.io/spring-security/site/faq/faq.html#faq-method-security-in-web-context – user227353

0

Thêm giao diện mới:

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

Thực hiện nó phục vụ người dùng của bạn và thử lại. Mùa xuân sẽ có thể thêm kiểm tra ủy quyền được yêu cầu bằng cách sử dụng proxy JDK.

Như một tùy chọn khác, bạn có thể định cấu hình Spring để sử dụng một số thư viện nặng hơn như Javassist hoặc thậm chí AspectJ.Trong trường hợp này, giao diện sẽ không cần thiết.

EDIT. Đảm bảo rằng global-method-security được khai báo trong cùng ngữ cảnh mùa xuân với bean dịch vụ người dùng của bạn.

+0

Không hoạt động khi thêm giao diện .. Tôi có nên chú thích phương pháp như tôi đã làm trong bài đăng của mình, không phải trong giao diện không? – Spacemonkey

+0

Có, chú thích thường được áp dụng ở bên thực hiện –

+1

Vui lòng hiển thị xml mùa xuân của bạn. Bạn có thể có hai bối cảnh mùa xuân (cho đậu và cho Spring MVC). Bạn có chắc chắn rằng elemnt bảo mật phương pháp toàn cục của bạn được định nghĩa trong cùng một ngữ cảnh với dịch vụ người dùng của bạn không? –

0

Các cách khác để làm cho nó hoạt là thêm đoạn mã sau vào security.xml bạn

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

Nó sẽ đảm bảo rằng chỉ quản trị viên mới có thể truy cập các tài nguyên bắt đầu bằng mẫu/người dùng /.

Các vấn đề liên quan