Shiro 实战

项目简介


背景 及 需求

背景
平台融合了多种用户(平台客户、后台运营者)
多种登录逻辑(面向客户的、面向运营人员的)混杂在一个项目中
需求
为后台运营系统增加权限
页面元素按照用户角色决定是否展示
难点
shiro难以对多个登陆逻辑、多个系统做出统一的处理,很难拆分出 不需要shiro 管理的面向客户的系统,也就是说需要拦截的东西是不确定的,不需要拦截的东西是确定的。

解决思路

想法一
刚开始想法错误,考虑到以后需求可能会将客户平台也纳入到shiro中,所以总想着将所有东西都划归到shiro下管理,但是当前系统需要拦截的东西是不确定的,反而不需要拦截的东西是确定的。走了很多弯路。
其中 loginUrl 即未授权重定向的页面是对应多个的,所以只能通过一个Action或Filter来做复杂判断和跳转。
shiro 核心过滤器如下

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/loginDispatcher.do"/>
<property name="unauthorizedUrl" value="/page/401"/>
<property name="filterChainDefinitions">
<value>
<!-- 静态资源允许访问 -->
/resource/** = anon
<!--用户平台允许访问-->
/bank/** = anon
<!--运营平台需要登录认证-->
/platform/** = authc
<!-- 其他资源需要认证 -->
/** = authc
</value>
</property>
</bean>
想法二
由于前台mvc层使用的是Struts2(各种漏洞、吐槽)、而且考虑到当前struts2的命名空间划分还是比较合理的,运营平台统一划分在 /platform下,转变思路,不去考虑使用shiro管理所有东西,把所有权限都放行,只拦截 /platform下的。
客户平台还是由原来的Filter管理

struts.xml

 <!-- 运营平台 -->
    <package name="platform" namespace="/platform" extends="struts-default">
        <action>
            ...
    </package >

shrio核心过滤器

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/login.jsp"/>
    <property name="unauthorizedUrl" value="/page/401"/>
    <property name="filterChainDefinitions">
        <value>
            <!--后台运营使用shrio管理-->
            /platform/** = authc
            <!-- 其他资源放开 -->
            /** = anon
        </value>
    </property>
</bean>

环境

  • JDK1.7
  • Tomcat1.8
  • Struts2 2.32
  • Spring 4.0.6
  • Hibernate 4.0.4
  • shiro 1.2.3

配置

web.xml

shiro的过滤器应该位于MVC(这里是struts2)层框架过滤器的上方

<!-- shiro的过滤器 -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
  <!-- struts2的过滤器 -->
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<!-- shiro的过滤器 -->
 <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 <!-- struts2的过滤器 -->
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
自定义登录逻辑 Realm

继承AuthorizingRealm

public class PlatformRealm extends AuthorizingRealm {
    ...
}

重写登录教研

@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        ...
    }

重写授权校验

@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    ...
 }

注册Realm给安全管理器

DefaultWebSecurityManager 安全管理器

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realms">
            <list>
                <ref bean="platformRealm"/>
            </list>
        </property>
    </bean>

~使用Shiro~

  • 登录逻辑重构 UsernamePasswordToken
    用户令牌
            UsernamePasswordToken token = new UsernamePasswordToken();
            token.setUsername("用户输入的用户名");
            token.setPassword("用户输入的密码");
    Subject
    可以理解为Shiro所管理的用户对象所
     Subject subject = SecurityUtils.getSubject();
     //登录
     subject.login(token);
    SimpleAuthenticationInfo
    认证及认证结果信息,其中user为登陆成功后 返还给客户端的用户对象。可以通过 User user = (User) subject.getPrincipal(); 获取。
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, "数据库中的密码", getName());
  • 权限校验
    注解方式
    : @RequiresPermissions(“你定义的权限名称”)应用在你的方法上。

    页面标签
    : <shiro:hasPermission name="user:create">


自定义url过滤器

  • shiro内置的 角色url过滤器校验的逻辑为且的关系,即满足多种角色才可以,一个用户即是platform.admin角色而且也是platform.operator角色才可以访问,代码如下
  • 先在的需求:需要两者满足其一即可,即或的关系。

      <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
           <property name="filterChainDefinitions">
                <value>
                /platform/home.do* = roles[platform.admin,platform.operator]
  • 自定义过滤器
    参考自ikaraide的博客

    public class CustomRolesAuthorizationFilter extends AuthorizationFilter {
    
        @Override  
        protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws Exception {
            Subject subject = getSubject(req, resp);
            String[] rolesArray = (String[]) mappedValue;  
    
            if (rolesArray == null || rolesArray.length == 0) { //没有角色限制,有权限访问  
                return true;  
            }
            for (String aRolesArray : rolesArray) {
                if (subject.hasRole(aRolesArray)) { //若当前用户是rolesArray中的任何一个,则有权限访问
                    return true;
                }
            }  
            return false;
        }  
    }
  • 配置

    <!-- 自定义的过滤器,用来判断当前用户是否是roleOrFilter["comm,test"]中的某个角色 -->
        <bean id="roleOrFilter" class="cn.ecotrans.web.shior.CustomRolesAuthorizationFilter" />

    注册该过滤器到shiro的过滤器链

      <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <!-- 添加各种验证过滤器 -->
            <property name="filters">
                <map>
                    <entry key="roleOrFilter" value-ref="roleOrFilter"/>
                </map>
            </property>
             ···
             ···
             ···

    使用

     /platform/** = roleOrFilter[platform.admin,platform.operator]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值