美文网首页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>

相关文章

  • 02_Spring整合Shiro实现认证授权

    Spring整合Shiro实现认证授权 1. 添加Shiro依赖 2. web.xml添加shiro的过滤器 3....

  • 3.21学习

    Shiro(整合thymeleaf):认证和授权的框架Swagger(整合thymeleaf):API实时更新工具...

  • SpringMVC整合Shiro

    摘要: SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话...

  • Shiro框架

    SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功...

  • springboot + shiro +cas 集成

    shiro 认证流程图: shiro 授权流程图: shiro 认证时序图: shiro + cas 认证时序图:...

  • 谈谈Shiro的原理及在SSM和SpringBoot两种环境下的

    在上一篇中,我已经对Shiro中认证和授权模块基本认证做了介绍,本篇主要介绍Shiro在SSM的工程中的整合使用方...

  • 基于shiro的权限设计

    shiro介绍 Apache shiro是一个权限控制框架,它将安全认证抽取出来,实现用户身份认证,权限授权,加密...

  • SpringBoot + Shiro 整合

    --本文记录了 SpringBoot + Shiro整合,包括 Shiro 登录认证(多个 Realm认证),Se...

  • Shiro安全框架

    1、Shiro概述 Shiro是一个安全框架,它将软件系统的安全认证相关功能抽取出来,实现用户身份认证,权限授权、...

  • shiro认证与授权

    shiro认证与授权 一.shiro认证方式-1(iniRealm)+授权 以maven项目为例 不采用数据库,只...

网友评论

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

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

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