java @PreAuthorize 不适用于方法安全规则和方法参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15360965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:20:58  来源:igfitidea点击:

@PreAuthorize does not work with method security rules and method parameters

javaspring-securityannotationsaspectj

提问by Spacemonkey

I am adding Spring Security to one Spring project. The architecture of the system is REST and user can access to different resources.

我正在将 Spring Security 添加到一个 Spring 项目中。系统架构为REST,用户可以访问不同的资源。

I would like to give access to personal information to administrators and users that are owners of this information. I have started simple: filtering user profile like this:

我想向作为此信息所有者的管理员和用户授予访问个人信息的权限。我开始很简单:像这样过滤用户配置文件:

In my service layerI wanted to use method annotations and include method parameters..

在我的服务层中,我想使用方法注释并包含方法参数..

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

But this is not working at all. Any user can see all profiles (admins and all users also) when this URL is requested (Web layer):

但这根本行不通。请求此 URL 时,任何用户都可以看到所有配置文件(管理员和所有用户)(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));
}

Here is my security.xml

这是我的 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="/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 have checked Spring Security 3.1 bookand apparently my configuration is as book suggests. I have read other Stack Overflow posts (hereand here) but I had no luck.

我检查了Spring Security 3.1 的书,显然我的配置是书上建议的。我已经阅读了其他 Stack Overflow 帖子(这里这里),但我没有运气。

Update:Added application-context.xml

更新:添加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:I have added spring-security-aspectsto POM and no changes. Other changes suggested in answers have been tested with but annotations such @PreAuthorizeare still not working. Cna this be a problem between contexts? Can be the usage of aspectJ the reason?

更新:我已经添加spring-security-aspects到 POM 中,没有任何变化。答案中建议的其他更改已经过测试,但此类注释@PreAuthorize仍然无效。这可能是上下文之间的问题吗?可能是aspectJ的使用原因吗?

What am I doing wrong?

我究竟做错了什么?

采纳答案by Spacemonkey

Finally I found solution. In SO I found some usefull answers. See hereand here.

最后我找到了解决方案。在 SO 中,我找到了一些有用的答案。请参阅此处此处

I moved global-method-securityto application-context.xmlwhich is the context of my services.

我感动global-method-securityapplication-context.xml这是我的服务范围内。

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

Where mode="aspectj"as Javadoc says:

mode="aspectj"为的Javadoc说:

...can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module.

...可用于指定应使用 AspectJ 而不是默认的 Spring AOP。如果设置,安全类必须与来自 spring-security-aspects 模块的 AnnotationSecurityAspect 编织在一起。

Of course, I have added to POM spring-security-aspects:

当然,我已经添加到 POM spring-security-aspects

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

回答by Arjun Thakur

The alternative way to make it work is to add the following code in your security.xml

使其工作的另一种方法是在您的 security.xml 中添加以下代码

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

It will ensure that only admin can access the resources starting with pattern /user/.

它将确保只有管理员可以访问以模式 /user/ 开头的资源。

回答by Maksym Demidas

Add new interface:

添加新界面:

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

Implement it in your user service and try again. Spring will be able add requested authorization checks using JDK proxies.

在您的用户服务中实现它并重试。Spring 将能够使用 JDK 代理添加请求的授权检查。

As another option you can configure Spring to use some more heavyweight libraries like Javassist or even AspectJ.In this case interface will be not necessary.

作为另一种选择,您可以将 Spring 配置为使用一些更重量级的库,例如 Javassist 甚至 AspectJ。在这种情况下,不需要接口。

EDIT.Make sure that global-method-securityis declared in the same spring context with your user service bean.

编辑。确保global-method-security在与您的用户服务 bean 相同的 spring 上下文中声明。