Проверка разрешения Shiro Authorization с использованием аннотации не работает - PullRequest
6 голосов
/ 12 октября 2011

Платформа: Shiro 1.1.0, Spring 3.0.5

Я пытаюсь защитить методы контроллера 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){    

Я что-то упустил?Пожалуйста, помогите.

Ответы [ 6 ]

9 голосов
/ 29 ноября 2011

Вы были абсолютно правы. Увидев ваш комментарий, я начал задумываться. Ну, тогда я обнаружил, что это не проблема реализации с Широ, но зависимости jar не были правильно настроены. Pom.xml от Shiro также должен иметь зависимость для 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, если вы использовали его в своей конфигурации. контекст: компонент-сканирование уже сканирует все аннотации.

Как только вы начнете тестирование, установите log4j в режим отладки или (лучше) трассировки. Всякий раз, когда вы запускаете свой сервер, вы найдете где-нибудь следующую запись в ваших журналах:

08: 16: 24 684 DEBUG Аннотация AwareAspectJAutoProxyCreator: 537 - Создание неявного прокси для бина 'userController' с 0 общими перехватчик и 1 специфический перехватчик

3 голосов
/ 25 ноября 2011

Думаю, Широ был построен, когда Spring 2.0 был на месте.Аннотации Широ (requireRoles и т. Д.) Хорошо работают для bean-компонентов, управляемых пружинным контейнером (сервисный слой), но не работают с аннотацией @Controller.Это связано с тем, что компонент @Controller сканируется компонентом Spring Framework.Я использовал АОП для решения проблемы.Ниже приведено решение, которое сработало для меня.Чтобы приведенное ниже решение работало, вы должны включить следующие четыре банки:

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

Создайте приведенный ниже аспект для аннотации (RequRoles).Вы можете использовать тот же принцип для создания точек для Требуется разрешение .

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 уже сканирует все аннотации.

2 голосов
/ 03 сентября 2013

Если вы избегаете Spring XML и используете в основном конфигурацию Java и аннотации, самый простой способ исправить это - добавить

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)

ко всем вашим @Controller классам.Вам нужен cglib на пути к классам.

1 голос
/ 21 июня 2012

Я использовал только весенний спящий пример из образца. Чтобы использовать аннотации, такие как @RequiresPermissions и другие, я попытался настроить конфигурацию из руководства shiro, настройку из этого поста, но мне не удалось скомпилировать или запустить действительные URL-адреса. Поэтому я только прокомментировал все @RequiresPermissions из ManageUserController и начал использовать его в реализации сервиса. Например, в DefaultUserService в методе getAllUsers я добавил аннотацию @RequiresPermissions («пользователь: управление»). Волшебно, теперь приложение работает как положено. Всякий раз, когда вызывается url manageUsers, он отображает страницу списка, если у пользователя есть роль user: manage, и выдает пользователя в / неавторизованный, если у пользователя нет такого разрешения.

Я даже настроил приложение для использования 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);
    }

Создает пять таблиц как | разрешения | | роли | | role_permissions | | пользователи | | users_roles |

И разрешения не зависят от других. В соответствии с новым RBAC у вас есть оба способа (явный и неявный) способ авторизации ресурсов.

0 голосов
/ 15 декабря 2017

У меня была такая же проблема. Мое исправление меняло мою версию джерси с 2.2 на 2.22.2, и все @RequiresPermissions работали на моих контроллерах.

0 голосов
/ 21 января 2017

Вам нужно написать 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;
}

Пример ShiroConfiguration на Github

...