美文网首页SSM+shiro等shiro
02_Spring整合Shiro实现认证授权

02_Spring整合Shiro实现认证授权

作者: 明天你好向前奔跑 | 来源:发表于2017-08-20 13:29 被阅读161次

    Spring整合Shiro实现认证授权

    1. 添加Shiro依赖

    <shiro.version>1.2.3</shiro.version>
    
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-aspectj</artifactId>
        <version>${shiro.version}</version>
    </dependency>
    

    2. web.xml添加shiro的过滤器

    添加shiro过滤器,对所有访问的url或action进行认证/权限控制
    //必须添加到Struts2的filter拦截器前
    <!-- shiro -->
    <filter>
        <!-- 过滤器代理:起到转发的作用,将请求转发给spring管理的id为shiroFilter的过滤器来处理 -->
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
        <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    3. applicationContext_shiro.xml

    applicationContext_shiro.xml对拦截的请求进行认证与授权
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- shiro过滤器工厂bean,相当于简介加载了9个内置过滤器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <!-- 安全管理器组件:核心组件 -->
            <property name="securityManager" ref="securityManager" />
    
            <!-- 认证相关配置:用户必须登陆才能访问资源,否则跳转到登录页面login.html -->
            <property name="loginUrl" value="/login.html" />
    
            <!-- 授权相关配置:当用户访问了没有权限的资源时,跳转到该页面error.html -->
            <property name="unauthorizedUrl" value="/error.html" />
            
            <!-- 添加各种过滤器 -->
            <property name="filters">
                <map>
                    <entry key="perms" value-ref="erpFilter"></entry>
                </map>
            </property>
    
            <!-- 过滤链定义: 哪些URL需要拦截,使用哪种过滤器来拦截 -->
            <property name="filterChainDefinitions">
                <value>
                    //无需认证即可访问的资源
                    /error.html=anon
                    /login_*=anon
                    
                    // 授权配置,用户拥有权限才能访问对应的资源
                    /goodstype.html=perms["商品类型"]
                    /goodstype_*=perms["商品类型"]
                    
                    /goods.html=perms["商品管理"]
                    /goods_*=perms["商品管理"]
                    
                    /store.html=perms["仓库管理"]
                    /store_*=perms["仓库管理"]
                    
                    /dep.html=perms["部门管理"]
                    /dep_*=perms["部门管理"]
                    
                    /emp.html=perms["员工管理"]
                    /emp_*=perms["员工管理"]
                    
                    /orders.html=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
                    /orders_*=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
                    /orderdetail_*=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
                    /store_mylist=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
                    /supplier_list=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
                    
                    /report_order.html=perms["销售统计图"]
                    /report_orderReport=perms["销售统计图"]
                    /report_trend.html=perms["销售趋势图"]
                    /report_orderTrend=perms["销售趋势图"]
                    
                    /storedetail.html=perms["库存查询"]
                    /storedetail_*=perms["库存查询"]
                    /storedetail_*=perms["库存查询"]
                    /store_*=perms["库存查询"]
                    /goods_*=perms["库存查询"]
                    /storeoper_myListByPage=perms["库存查询"]
                    
                    /storealert.html=perms["库存预警"]
                    /storedetail_sendStorealertEmail=perms["库存预警"]
                    /storedetail_storealert=perms["库存预警"]
                    
                    /storeoper.html=perms["库存变更查询"]
                    /storeoper_*=perms["库存变更查询"]
                    
                    /pwd.html=perms["重置密码"]
                    /emp_listByPage=perms["重置密码"]
                    /login_resetPwd=perms["重置密码"]
                    
                    /role.html=perms["角色设置"]
                    /role_*=perms["角色设置"]
                    
                    /role_menu.html=perms["角色权限设置"]
                    /role_*=perms["角色权限设置"]
                    
                    /emp_role.html=perms["用户角色设置"]
                    /emp_list=perms["用户角色设置"]
                    /emp_readEmpRole=perms["用户角色设置"]
                    /emp_updateEmpRole=perms["用户角色设置"]
                    
                    //必须进行认证的资源,认证必须写在授权下面
                    /*.html=authc
                    /*=authc
                </value>
            </property>
        </bean>
    
        <!-- shiro的核心:大脑, 安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="erpFilter">
            <!-- 安全管理器中使用erpRealm执行认证 -->
            <property name="realm" ref="erpRealm" />
        </bean>
    
        <!-- 注册realm认证/授权:erpReam中告诉shiro用户拥有什么权限,shiro拿过来与配置进行比较 -->
        <bean id="erpRealm" class="com.itdream.erp.realms.ErpRealm">
            <property name="empBiz" ref="empBiz" />
            <property name="menuBiz" ref="menuBiz" />
        </bean>
        
        <!-- 注册自定义权限过滤器:多个权限访问一个url资源,满足其中一个权限就可以访问 -->
        <bean id="erpFilter" class="com.itdream.erp.filter.ErpAuthorizationFilter"></bean>
    

    </beans>

    4. 用户登陆认证

    /**
     * 用户登录
     */
    public void checkUser() {
        try {
            // shiro来执行用户登录
            // 1.创建令牌,传入用户登录账号和密码
            UsernamePasswordToken token = new UsernamePasswordToken(username, pwd);
            // 2. 获得主题subject
            Subject subject = SecurityUtils.getSubject();
            // 3. 执行登陆
            subject.login(token);
            WebUtils.ajaxReturn(true, "登陆成功");
        } catch (AuthenticationException e) {
            log.error("登录失败", e);
            WebUtils.ajaxReturn(false, "登陆失败");
        }
    }
    

    5. Realm:用户身份信息:权限控制及用户登录认证

    告诉shiro如何判定用户是否正确以及用户拥有哪些权限
    public class ErpRealm extends AuthorizingRealm {
    
        private IEmpBiz empBiz;
        private IMenuBiz menuBiz;
    
        @Override
        // 授权方法:告诉shiro当前登陆用户有哪些权限
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
            // 获得当前的登陆用户
            Emp emp = (Emp) paramPrincipalCollection.getPrimaryPrincipal();
            List<Menu> menuList = menuBiz.getMenusByEmpuuid(emp.getUuid());
    
            // 实例化shiro权限信息
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 告诉shiro当前登录用户有哪些权限,这些权限访问的url在配置文件applicationContext_shiro.xml中配置
            for (Menu menu : menuList) {
                // 添加用户拥有的菜单名作为权限配置,用户拥有该菜单名,就有访问该菜单名对应的配置的页面的访问权限(据配置而定)
                info.addStringPermission(menu.getMenuname());
            }
            return info;
        }
    
        @Override
        // 认证方法:判定用户是否正确登陆
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken)
                throws AuthenticationException {
            // 获取存储在token中的账号密码
            UsernamePasswordToken token = (UsernamePasswordToken) paramAuthenticationToken;
            String username = token.getUsername();
            char[] password = token.getPassword();
            String pwd = new String(password);
            // 查询数据库用户是否存在
            Emp emp = empBiz.findByUsernameAndPwd(username, pwd);
            if (emp != null) {
                // 返回认证信息
                // principal:主角,就是当前用户
                // credentials:证书或凭证,这里我们用的是密码
                // realmName:当前realm的名称
                return new SimpleAuthenticationInfo(emp, pwd, getName());
            }
            // 不存在直接返回null
            return null;
        }
    
        public void setEmpBiz(IEmpBiz empBiz) {
            this.empBiz = empBiz;
        }
    
        public void setMenuBiz(IMenuBiz menuBiz) {
            this.menuBiz = menuBiz;
        }
    }
    
    写完ErpRealm要去applicationContext_shiro.xml中注册,并将注入shiro核心SecurityManager,shiro在执行login时会调用这个realm进行认证以及授权
    
    
    在applicationContext_shiro的过滤链配置权限控制:
        告诉shiro什么资源有什么权限才可以访问
        <!-- 过滤链定义: 哪些URL需要拦截,使用哪种过滤器来拦截 -->
        <property name="filterChainDefinitions">
            <!--可以直接放行的资源-->
            /error.html=anon
            /login_*=anon
    
            <!--权限控制,拥有指定权限才能访问指定资源-->
            /goodstype.html=perms["商品类型"]
            /goodstype_*=perms["商品类型"]
    
            <!--认证:未通过认证不能进行访问的资源-->
            /*.html=authc
            /*=authc
        </property>
    

    6. 自定义权限过滤器

    权限配置完成后,会出现多个权限访问同一个url的情况,这种情况只能使用:
        /orders.html=perms["未审核订单","未确认订单"]来配置,如果分开配置后面的会覆盖前面的.
        但是这种写法,shiro默认是必须同时拥有两种权限定义:未审核电脑,未确认订单才能访问。
        因此自定义权限过滤器覆盖默认权限过滤器,使它满足其中一个权限定义就能访问对应资源
    
    
    自定义权限过滤器,继承AuthorizationFilter
    
    /**
     * 自定义权限过滤器,让满足其中一个perms就可以访问该url
     */
    public class ErpAuthorizationFilter extends AuthorizationFilter {
    
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
                throws Exception {
            Subject subject = getSubject(request, response);
            String[] perms = (String[]) mappedValue;
    
            if (perms != null && perms.length > 0) {
                if (perms.length == 1) {
                    if (!subject.isPermitted(perms[0])) {// 如果配置文件只设置了一个perm条件且不满足,返回false,如果没有则会出循环执行true
                        return false;
                    }
                } else {
                    for (String perm : perms) {
                        if (subject.isPermitted(perm)) {// 一旦该用户权限有一个符合perms条件了,就让其通过
                            return true;
                        }
                    }
                    // 设置了权限但用户一个条件都不符合就返回false
                    return false;
                }
            }
            // 如果配置文件中没有配置perms,直接返回true
            return true;
        }
    } 
    
    
    applicationContext_shiro.xml注册并使用该自定义过滤器:
    
    <!-- 注册自定义权限过滤器 -->
    <bean id="erpFilter" class="com.itdream.erp.filter.ErpAuthorizationFilter"></bean>
    
    在shiro过滤器工厂bean中添加自定义过滤器
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 添加各种过滤器 -->
        <property name="filters">
            <map>
                <entry key="perms" value-ref="erpFilter"></entry>
            </map>
        </property>
    </bean>
    
    在shiro核心:securityManager的bean上添加depends-on
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="erpFilter">
            <!-- 安全管理器中使用erpRealm执行认证 -->
            <property name="realm" ref="erpRealm" />
        </bean>

    相关文章

      网友评论

      • 青蛙过河:授权这一块比较晕,看了您的代码,我想问下,用springboot写的话,没有applicationContext_shiro.xml文件,那么这个自定义拦截的url需要写在哪里呢?
        青蛙过河:@明天你好向前奔跑 嗯呢 ,好的,我也继续研究吧
        明天你好向前奔跑:Springboot集成Shiro这一块我还没试过,这段时间我抽个时间试一下,总结一篇经验出来。

      本文标题:02_Spring整合Shiro实现认证授权

      本文链接:https://www.haomeiwen.com/subject/yjjfdxtx.html