Shiro授权使用Annotation无效的权限检查

时间:2011-10-12 17:01:49

标签: spring shiro

平台:Shiro 1.1.0,Spring 3.0.5

我正在尝试使用Shiro注释来保护MVC Controller方法。但是注释有问题。普通电话正常工作。 Shiro调试中也没有具体的内容。

我的shiro配置:

<!-- Security Manager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="sessionMode" value="native" />
        <property name="realm" ref="jdbcRealm" />
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

    <!-- Caching -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManager" ref="ehCacheManager" />
    </bean>

    <bean id="ehCacheManager"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />

    <bean id="sessionDAO"
        class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" />

    <bean id="sessionManager"
        class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="sessionDAO" ref="sessionDAO" />
    </bean>


    <!-- JDBC Realm Settings -->
    <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
        <property name="name" value="jdbcRealm" />
        <property name="dataSource" ref="dataSource" />
        <property name="authenticationQuery"
            value="SELECT password FROM system_user_accounts WHERE username=? and status=1" />
        <property name="userRolesQuery"
            value="SELECT role_name FROM system_roles r, system_user_accounts u, system_user_roles ur WHERE u.user_id=ur.user_id AND r.role_id=ur.role_id AND u.username=?" />
        <property name="permissionsQuery"
            value="SELECT permission_name FROM system_roles r, system_permissions p, system_role_permission rp WHERE r.role_id=rp.role_id AND p.permission_id=rp.permission_id AND r.role_name=?" />
        <property name="permissionsLookupEnabled" value="true"></property>
    </bean>

    <!-- Spring Integration -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    <!-- Enable Shiro Annotations for Spring-configured beans. Only run after 
        the lifecycleBeanProcessor has run: -->
    <bean id="annotationProxy"
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor" />
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

    <!-- Secure Spring remoting: Ensure any Spring Remoting method invocations 
        can be associated with a Subject for security checks. -->
    <bean id="secureRemoteInvocationExecutor"
        class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
        <property name="securityManager" ref="securityManager" />
    </bean>

    <!-- Shiro filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/login" />
        <property name="successUrl" value="/dashboard" />
        <property name="unauthorizedUrl" value="/error" />
        <property name="filterChainDefinitions">
            <value> 
                <!-- !!! Order matters !!! -->
                /authenticate = anon
                /login = anon
                /logout = anon
                /error = anon
                /** = authc
            </value>
        </property>
    </bean>

我可以正常使用以下内容:

@RequestMapping(value="/form") 
public String viewPatientForm(Model model, @RequestParam(value="patientId", required=false) Long patientId){    
   if (!SecurityUtils.getSubject().isPermitted("hc:viewPatient")){
      logger.error("Operation not permitted");
      throw new AuthorizationException("No Permission"); 
   }
}

但下面的内容不起作用:

@RequiresPermissions("hc:patientView")
    @RequestMapping(value="/form")
    public String viewPatientForm(Model model, @RequestParam(value="patientId", required=false) Long patientId){    

我错过了什么吗?请帮忙。

6 个答案:

答案 0 :(得分:9)

你是对的。看到你的评论后,我开始考虑一下。那么我发现它不是Shiro的实现问题,但是jar依赖没有正确配置。 Shiro的pom.xml也应该依赖于cglib2。

所以下面的修改对我有用:

  1. 包括所有这四个jar文件。

      

    aspectjrt-1.6.11.jar,
      aspectjweaver-1.6.12.jar,
      CGLIB-2.2.2.jar,
      ASM-3.3.1.jar,

  2.      如果您正在使用maven,那么:

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.11</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.12</version>
    </dependency>    
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
    

    最后将aop:aspectj-autoproxy放在webApplicationContext.xml

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!-- Annotation, so that it's easier to search controllers/components -->
    <context:component-scan base-package="com.pepsey.soft.web.controller"/>
    

    注意:上述两个配置应放在同一个spring-webApplicationContext.xml中。否则它将无法工作。此外,如果您在配置中使用了它,则删除context:annotation-config。 context:component-scan已经扫描了所有注释。

    开始测试后,将log4j设置为debug或(更好)跟踪模式。每当您启动服务器时,您都会在日志中找到以下条目:

      

    08:16:24,684 DEBUG AnnotationAwareAspectJAutoProxyCreator:537 -   使用0 common创建bean'userController'的隐式代理   拦截器和1个特定拦截器

答案 1 :(得分:3)

猜猜Shiro是在Spring 2.0到位时构建的。 Shiro的注释(RequiresRoles等...)适用于spring容器托管bean(服务层),但它不适用于@Controller注释。这是因为@Controller是由spring框架扫描的组件。我使用AOP解决了这个问题。以下是适合我的解决方案。 要使以下解决方案起作用,您必须包括以下四个罐子:

aspectjrt-1.6.11.jar
aspectjweaver-1.6.12.jar
cglib-2.2.2.jar
asm-3.3.1.jar

如果您正在使用maven,那么以下配置会有所帮助。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.6.11</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.12</version>
</dependency>    
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency> 

以下是控制器类

import org.apache.shiro.authz.annotation.RequiresRoles;

@Controller
public class PatientController {

    @RequiresRoles(“admin,warden”)
    @RequestMapping(value="/form") 
    public String viewPatientForm(Model model,  @RequestParam(value="patientId", required=false) Long patientId){    

        return “somePatientFormJsp”;
    }
}

为注释创建以下Aspect(RequiresRoles)。您可以使用相同的原则为 RequiresPermission 创建切入点。

import java.util.Arrays;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class WebAuthorizationAspect {

    @Before("@target(org.springframework.stereotype.Controller) && @annotation(requiresRoles)")
    public void assertAuthorized(JoinPoint jp, RequiresRoles requiresRoles) {
        SecurityUtils.getSubject().checkRoles(Arrays.asList(requiresRoles.value()));
    }
}

在spring-webApplicationContext.xml中,无论你提到过哪里

<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Annotation, so that it's easier to search controllers/components -->
<context:component-scan base-package="com.example.controller"/>

注意:以上两种配置应放在相同 spring-webApplicationContext.xml中。否则它将无法工作。此外删除 上下文:annotation-config 如果您已在配置中使用它。 context:component-scan 已经扫描了所有注释。

答案 2 :(得分:2)

如果您要避免使用Spring XML并主要使用Java和注释配置,最简单的解决方法是添加

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)

到您的所有@Controller课程。你需要在类路径上使用cglib。

答案 3 :(得分:1)

我只使用了样本中的spring-hibernate示例。要使用像@RequiresPermissions这样的注释和其他我尝试从shiro手册配置,从这篇文章配置,但我要么编译或运行有效的URL不成功。所以我只评论了ManageUserController中的所有@RequiresPermissions,并开始在服务实现中使用它。例如,在getAllUsers方法的DefaultUserService中,我添加了注释@RequiresPermissions(“user:manage”)。现在神奇地应用程序按预期工作。每当调用url manageUsers时,如果用户具有角色用户,则显示列表页面:如果用户没有该权限,则管理并将用户抛出/未授权。

我甚至将应用程序配置为使用mysql。为了根据新的RBAC(http://www.stormpath.com/blog/new-rbac-resource-based-access-control)使权限独立于角色,我创建了一个名为Permission的新类

@Entity
@Table(name = "permissions")
@Cache(usage= CacheConcurrencyStrategy.READ_WRITE)
public class Permission {
    @Id
    @GeneratedValue
    private Long id;
    private String element;
    private String description;
    // setter and getter

现在,Role类配置为

 @CollectionOfElements
    @JoinTable(name="roles_permissions")
    @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
    public Set<Permission> getPermissions() {
        return permissions;
    }

最后SampleRealm为

 for (Role role : user.getRoles()) {
        info.addRole(role.getName());

        System.out.println("Roles " + role.getName());

        // Get permissions first
        Set<Permission> permissions = role.getPermissions();
        Set<String> permissionsStrings = new HashSet<String>();

        for (Permission permission : permissions) {
            permissionsStrings.add(permission.getelement());
            System.out
                    .println("Permissions " + permission.getelement());
        }

        info.addStringPermissions(permissionsStrings);
    }

它创建了五个表 |权限| |角色| | roles_permissions | |用户| | users_roles |

权限独立于任何其他权限。根据新的RBAC,您有两种方式(显式和隐式)授权资源。

答案 4 :(得分:0)

您需要编写AuthorizationAttributeSourceAdvisor以根据Shiro documentation启用Shiro的注释bean

如果您已写过ShiroConfiguration课程,请确保包括以下内容:

@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
}

@Bean
@ConditionalOnMissingBean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultSecurityManager securityManager) {
    // This is to enable Shiro's security annotations
    AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    sourceAdvisor.setSecurityManager(securityManager);
    return sourceAdvisor;
}

@ConditionalOnMissingBean
@Bean(name = "defaultAdvisorAutoProxyCreator")
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
    proxyCreator.setProxyTargetClass(true);
    return proxyCreator;
}

Example ShiroConfiguration on Github

答案 5 :(得分:0)

我遇到了同样的问题。我的修复是将我的球衣版本从2.2改为2.22.2并且所有@RequiresPermissions都在我的控制器上工作。