복붙노트

[SPRING] 주석을 사용하여 시로 권한 부여 권한 검사가 작동하지 않습니다.

SPRING

주석을 사용하여 시로 권한 부여 권한 검사가 작동하지 않습니다.

플랫폼 : Shiro 1.1.0, Spring 3.0.5

Shiro 주석을 사용하여 MVC Controller 메서드를 보호하려고합니다. 그러나 주석에 문제가 있습니다. 일반 전화는 정상적으로 작동합니다. 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){    

내가 놓친 게 있니? 도와주세요.

해결법

  1. ==============================

    1.당신은 절대적으로 옳았습니다. 당신의 코멘트를보고 나서, 나는 그것을 생각하기 시작했다. 그럼 Shiro의 구현 문제가 아니라는 것을 알았지 만 항아리 의존성은 제대로 구성되지 않았습니다. Shiro의 pom.xml도 cglib2에 대한 종속성이 있어야합니다.

    당신은 절대적으로 옳았습니다. 당신의 코멘트를보고 나서, 나는 그것을 생각하기 시작했다. 그럼 Shiro의 구현 문제가 아니라는 것을 알았지 만 항아리 의존성은 제대로 구성되지 않았습니다. Shiro의 pom.xml도 cglib2에 대한 종속성이 있어야합니다.

    그래서 아래 변경 사항이 저에게 효과적이었습니다.

    이 4 개의 jar 파일을 모두 포함하십시오.

  2. ==============================

    2.추측 Shiro는 봄 2.0이있을 때 건축되었다. Shiro의 주석 (RequiresRoles 등)은 스프링 컨테이너로 관리되는 bean (서비스 계층)에서 잘 작동하지만 @Controller annotation에서는 작동하지 않습니다. 이것은 @Controller가 스프링 프레임 워크에 의해 구성 요소 스캔되고 있기 때문입니다. 문제를 해결하기 위해 AOP를 사용했습니다. 아래는 나를 위해 일한 해결책입니다. 아래의 솔루션을 사용하려면 아래의 네 가지 병을 포함해야합니다.

    추측 Shiro는 봄 2.0이있을 때 건축되었다. Shiro의 주석 (RequiresRoles 등)은 스프링 컨테이너로 관리되는 bean (서비스 계층)에서 잘 작동하지만 @Controller annotation에서는 작동하지 않습니다. 이것은 @Controller가 스프링 프레임 워크에 의해 구성 요소 스캔되고 있기 때문입니다. 문제를 해결하기 위해 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)에 대해 아래의 Aspect를 만듭니다. 동일한 원리를 사용하여 RequiresPermission에 대한 pointcut을 만들 수 있습니다.

    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 참고 : 위의 두 구성은 동일한 spring-webApplicationContext.xml에 함께 있어야합니다. 그렇지 않으면 작동하지 않습니다. 또한 컨텍스트를 제거하십시오 : 주석 설정 (config)을 구성에 사용한 경우. 컨텍스트 : component-scan은 이미 모든 주석을 스캔합니다.

  3. ==============================

    3.Spring XML을 피하고 주로 자바와 주석 설정을 사용한다면, 이것을 수정하는 가장 쉬운 방법은

    Spring XML을 피하고 주로 자바와 주석 설정을 사용한다면, 이것을 수정하는 가장 쉬운 방법은

    @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
    

    모든 @Controller 클래스에. classpath에 cglib가 필요합니다.

  4. ==============================

    4.나는 샘플에서 스프링 - 동면 예제만을 사용했다. @RequiresPermissions와 같은 주석을 사용하려면 shiro 매뉴얼에서 구성을 시도했으나이 게시물의 구성은 유효하지만 컴파일 또는 실행에 실패했습니다. 그래서 저는 ManageUserController의 모든 @RequiresPermissions에 대해서만 주석을 달고 서비스 구현에 사용하기 시작했습니다. 예 : getAllUsers 메소드의 DefaultUserService에 @RequiresPermissions ( "user : manage") 주석을 추가했습니다. 마술처럼 지금은 응용 프로그램이 예상대로 작동합니다. url manageUsers가 호출 될 때마다 사용자에게 user : role 역할이있는 경우 목록 페이지를 표시하고 사용자에게 해당 권한이없는 경우 사용자를 / unauthorized로 throw합니다.

    나는 샘플에서 스프링 - 동면 예제만을 사용했다. @RequiresPermissions와 같은 주석을 사용하려면 shiro 매뉴얼에서 구성을 시도했으나이 게시물의 구성은 유효하지만 컴파일 또는 실행에 실패했습니다. 그래서 저는 ManageUserController의 모든 @RequiresPermissions에 대해서만 주석을 달고 서비스 구현에 사용하기 시작했습니다. 예 : getAllUsers 메소드의 DefaultUserService에 @RequiresPermissions ( "user : manage") 주석을 추가했습니다. 마술처럼 지금은 응용 프로그램이 예상대로 작동합니다. url manageUsers가 호출 될 때마다 사용자에게 user : role 역할이있는 경우 목록 페이지를 표시하고 사용자에게 해당 권한이없는 경우 사용자를 / unauthorized로 throw합니다.

    심지어 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);
        }
    

    5 개의 테이블을 다음과 같이 생성합니다. | 사용 권한 | | 역할 | | roles_permissions | | 사용자 | | users_roles |

    권한은 다른 사람과 독립적입니다. 새 RBAC에 따르면 리소스를 승인하는 두 가지 방법 (명시 적 및 암시 적)이 있습니다.

  5. ==============================

    5.Shiro 문서에 따라 Shiro의 주석 bean을 사용하려면 AuthorizationAttributeSourceAdvisor를 작성해야합니다.

    Shiro 문서에 따라 Shiro의 주석 bean을 사용하려면 AuthorizationAttributeSourceAdvisor를 작성해야합니다.

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

    Github의 ShiroConfiguration 예제

  6. ==============================

    6.나는 똑같은 문제가 있었다. 내 고지 버전이 2.2에서 2.22.2로 변경되었고 모든 @RequiresPermissions가 내 컨트롤러에서 작동했습니다.

    나는 똑같은 문제가 있었다. 내 고지 버전이 2.2에서 2.22.2로 변경되었고 모든 @RequiresPermissions가 내 컨트롤러에서 작동했습니다.

  7. from https://stackoverflow.com/questions/7743749/shiro-authorization-permission-check-using-annotation-not-working by cc-by-sa and MIT license