### shiro自定义filter【解决某个请求 需要同时拥有多种权限】

来源:互联网 发布:罗宾 知乎 编辑:程序博客网 时间:2024/05/18 07:56

=============自定义shiro Filter。解决问题:

==一个action对应多个权限

====添加分区时,不仅要有分区subArea权限,还要有区域Area的权限。

===findAll()下拉框选择 分区所属的区域。

===于是Spring配置shiro:如下:

/areaAction_findAll.action = perms["areaAction","subAreaAction"]

======配置完毕,结果导致:下拉框 区域回显失败。

======原因:perms权限对应的过滤器PermissionAuthorizationFilter源码中,要求:

/areaAction_findAll.action = perms["areaAction","subAreaAction"]<!-- ===没授权.findAll请求,匹配两个权限任意一个 -->

【多个权限之间要求是同时拥有所有权限】。====但这种配置却是指:拥有多种权限的任一种都放行:或关系。

======所以过滤器没通过。

======过滤器PermissionAuthorizationFilter源码:

=====解决思路:重写PermissionAuthorizationFilterisAccessAllowed()。。

=====######===很滑稽很无奈的坑。基础不熟练吧。

===【自定义的filter没有在web.xml配置】。导致报错依旧。。。伤心。。。配置完毕,一切ok 

====eclipse直接new Filter不用手动添加配置。Java web三大组件:servlet、filter、listener。

方案如下:

=========================



我的shiro之旅:自定义filter

转载 2016年06月23日 16:46:26

1. shiro的filter介绍

Filter NameClassanonorg.apache.shiro.web.filter.authc.AnonymousFilterauthcorg.apache.shiro.web.filter.authc.FormAuthenticationFilterauthcBasicorg.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilterlogoutorg.apache.shiro.web.filter.authc.LogoutFilternoSessionCreationorg.apache.shiro.web.filter.session.NoSessionCreationFilterpermsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilterportorg.apache.shiro.web.filter.authz.PortFilterrestorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilterrolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFiltersslorg.apache.shiro.web.filter.authz.SslFilteruserorg.apache.shiro.web.filter.authc.UserFilter

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/login" />
        <property name="successUrl" value="/home" />
        <property name="unauthorizedUrl" value="/unauthorized" />
        <!-- filters一般不需要定义,除非自定义filter覆盖原来的时候,需要定义 -->
        <!-- <property name="filters">
            <map>
                <entry key="authc">
                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
                </entry>
            </map>
        </property> -->
        <property name="filterChainDefinitions">
            <value>
                /admin = authc,roles[admin]
                /edit = authc,perms[admin:edit]
                /home = user
                /** = anon
            </value>
        </property>
    </bean>
loginUrl: 当用户没有登录的时候,会重发一个login请求,引导用户去登录
successUrl:是当用户登录成功,转发home请求
unauthorizedUrl指如果请求失败,重发/unauthorized请求,引导用户到认证异常错误页面

如我们在filterChainDefinitions里配置了/admin=authc,roles[admin],那么/admin这个请求会由org.apache.shiro.web.filter.authc.FormAuthenticationFilterorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter这两个filter来处理,其中authc,roles只是filter的别名。如要更改别名,可以通过filters来改变。如上面的配置 
 <property name="filters">
            <map>
                <entry key="authc">
                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
                </entry>
            </map>
        </property>
把PassThruAuthenticationFilter添加别名为authc,这时/admin请求会交给PassThruAuthenticationFilter处理,替换了原来由FormAuthenticationFilter来处理。

由此一来,如果有些特殊的请求需要特殊处理,就可以自己写一个filter,添加一个别名,如:
<property name="filters">
            <map>
                <entry key="new">
                    <bean class="com.text.newFilter" />
                </entry>
            </map>
        </property>


2. shiro自定义filter

使用shiro的时候,比较常用的filter有anon,authc,roles和perms。当我们想定义某个链接是拥有某些权限的用户才可以访问的时候,我们可以这样定义。/xx = roles[A,B]。在shiro中,表示当前用户同时拥有A,B两种角色才可以访问/xx这个链接,是一种&&(与)的关系

RolesAuthorizationFilter这样一个类,这个类就是定义roles的filter。

01public class RolesAuthorizationFilter extends AuthorizationFilter {
02 
03    //TODO - complete JavaDoc
04 
05    @SuppressWarnings({"unchecked"})
06    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
07 
08        Subject subject = getSubject(request, response);
09        String[] rolesArray = (String[]) mappedValue;
10 
11        if (rolesArray == null || rolesArray.length == 0) {
12            //no roles specified, so nothing to check - allow access.
13            return true;
14        }
15 
16        Set<String> roles = CollectionUtils.asSet(rolesArray);
17        return subject.hasAllRoles(roles);
18    }
19 
20}

上面定义了subject.hasAllRoles(roles);就是当前用户必须拥有定义的所有角色才会返回true。但有时候,我们需要当前用户拥有定义的其他一个角色就可以访问,那就需要写自己的filter。也很简单,代码以下:

01public class AnyRolesAuthorizationFilter extends AuthorizationFilter {
02 
03     
04    @Override
05    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
06 
07        Subject subject = getSubject(request, response);
08        String[] rolesArray = (String[]) mappedValue;
09 
10        if (rolesArray == null || rolesArray.length == 0) {
11            // no roles specified, so nothing to check - allow access.
12            return true;
13        }
14 
15        Set<String> roles = CollectionUtils.asSet(rolesArray);
16        for (String role : roles) {
17            if (subject.hasRole(role)) {
18                return true;
19            }
20        }
21        return false;
22    }
23 
24}

从上面的代码可以看到,当遍历,发现当前用户拥有定义的其中一个角色就立刻返回true,否则返回false。

定义好filter,只需要代码默认的roles即可。

01<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
02        <property name="securityManager" ref="securityManager" />
03        <property name="loginUrl" value="/security/login.html" />
04        <property name="successUrl" value="/home.html" />
05        <property name="unauthorizedUrl" value="/security/unauthorized.html" />
06        <property name="filters">
07            <map>
08                <entry key="anyRoles" value-ref="anyRolesAuthorizationFilter" />
09            </map>
10        </property>
11        <property name="filterChainDefinitions">
12            <value>
13                                /admin = anyRoles[admin1,admin2]
14                /** = anon
15            </value>
16        </property>
17    </bean>
perms的filter也同理。看看源码:

01public class PermissionsAuthorizationFilter extends AuthorizationFilter {
02 
03    //TODO - complete JavaDoc
04 
05    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
06 
07        Subject subject = getSubject(request, response);
08        String[] perms = (String[]) mappedValue;
09 
10        boolean isPermitted = true;
11        if (perms != null && perms.length > 0) {
12            if (perms.length == 1) {
13                if (!subject.isPermitted(perms[0])) {
14                    isPermitted = false;
15                }
16            } else {
17                if (!subject.isPermittedAll(perms)) {
18                    isPermitted = false;
19                }
20            }
21        }
22 
23        return isPermitted;
24    }
25}

自定义的filter:

01public class AnyPermissionsAuthorizationFilter extends AuthorizationFilter {
02 
03    @Override
04    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
05        Subject subject = getSubject(request, response);
06        String[] perms = (String[]) mappedValue;
07 
08        for (String perm : perms) {
09            if (subject.isPermitted(perm)) {
10                return true;
11            }
12        }
13         
14        return false;
15    }
16 
17}

配置使用自定义filter

01<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
02        <property name="securityManager" ref="securityManager" />
03        <property name="loginUrl" value="/security/login.html" />
04        <property name="successUrl" value="/home.html" />
05        <property name="unauthorizedUrl" value="/security/unauthorized.html" />
06        <property name="filters">
07            <map>
08                <entry key="anyPerms" value-ref="anyPermissionsAuthorizationFilter"/>
09            </map>
10        </property>
11         
12            <value>
13                /admin/add = anyPerms["admin:delete","admin:add"]
14                /** = anon
15            </value>
16        </property>
17    </bean>

当用户请求/admin/add时,就会调用自定义的AnyPermissionsAuthorizationFilter来执行。

原创粉丝点击