平台: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){
我错过了什么吗?请帮忙。
答案 0 :(得分:9)
你是对的。看到你的评论后,我开始考虑一下。那么我发现它不是Shiro的实现问题,但是jar依赖没有正确配置。 Shiro的pom.xml也应该依赖于cglib2。
所以下面的修改对我有用:
aspectjrt-1.6.11.jar,
aspectjweaver-1.6.12.jar,
CGLIB-2.2.2.jar,
ASM-3.3.1.jar,
<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;
}
答案 5 :(得分:0)
我遇到了同样的问题。我的修复是将我的球衣版本从2.2改为2.22.2并且所有@RequiresPermissions都在我的控制器上工作。