6

平台:Shiro 1.1.0、Spring 3.0.5

我正在尝试使用 Shiro 注释来保护 MVC 控制器方法。但是注释有问题。定期通话工作正常。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){    

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

4

6 回答 6

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,

如果您使用的是 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 设置为调试或(更好的)跟踪模式。每当您启动服务器时,您都会在日志中的某处找到以下条目:

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

于 2011-11-29T03:11:38.120 回答
3

Guess 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”;
    }
}

为注释创建以下方面 (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中。否则它将无法正常工作。此外,如果您在配置中使用了context:annotation-config ,请删除它。 context:component-scan已经扫描了所有的注解。

于 2011-11-25T05:08:10.447 回答
3

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

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)

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

于 2013-09-03T12:40:37.263 回答
1

我只使用了示例中的 spring-hibernate 示例。要使用 @RequiresPermissions 之类的注释和其他注释,我尝试了 shiro 手册中的配置,这篇文章中的配置,但我要么编译失败,要么运行有效的 url。所以我只注释了来自 ManageUserController 的所有 @RequiresPermissions 并开始在服务实现中使用它。例如,在getAllUsers 方法的DefaultUserService 中,我添加了注释@RequiresPermissions("user:manage")。神奇的是,现在该应用程序按预期工作。每当调用 url manageUsers 时,如果用户具有角色 user:manage,它会显示列表页面,如果用户没有该权限,则将用户扔到 /unauthorized。

我什至将应用程序配置为使用 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

现在角色类配置为

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

它创建五个表为 | 权限 | | 角色 | | 角色权限 | | 用户 | | 用户角色 |

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

于 2012-06-21T17:26:13.233 回答
0

您需要根据Shiro 文档AuthorizationAttributeSourceAdvisor编写启用 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;
}

ShiroConfigurationGithub 上的示例

于 2017-01-21T13:32:15.293 回答
0

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

于 2017-12-15T07:15:54.830 回答