Shiro-菜鸟实战篇-shiro集成spring

环境搭建

创建Maven工程,导入坐标

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.12.1</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.1.10.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.12.1</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.10.RELEASE</version>
  </dependency>
  <!--spring和aspectj框架整合的模块-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.10.RELEASE</version>
  </dependency>
  <!--spring支持jdbc编程模块-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.10.RELEASE</version>
  </dependency>
   <!--mysql驱动-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.20</version>
  </dependency>
  <!--数据库连接池-->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.20</version>
  </dependency>
  <!--mybatis-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
  </dependency>
  <!--mybatis和spring整合依赖包-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.2</version>
  </dependency>
  <!--spring mvc-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.10.RELEASE</version>
  </dependency>
  <!--java web -->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
  </dependency>
  <dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
  </dependency>
  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2</version>
  </dependency>
  <!--spring-json依赖-->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.8</version>
  </dependency>
   <!--文件上传-->
  <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
  </dependency>
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.4.1</version>
  </dependency>
  <dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.8.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.1</version>
  </dependency>
</dependencies>

来看下之前我们创建的ShiroUtil,然后把它通过spring ioc容器进行管理
Shiro-菜鸟实战篇-shiro集成spring_第1张图片
//1.初始化shiro的安全管理器
DefaultSecurityManager securityManager=new DefaultSecurityManager();

<bean name="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
</bean>

Realm realm=new ShiroRealm();

<!--自定义的realm,交给spring ioc容器来管理-->
<bean name="realm" class="com.hsy.sys.shiro.ShiroRealm"/>

//使用第3方缓存创建缓存管理器
CacheManager cacheManager=new EhCacheManager();

<!--缓存管理器cacheManager,交给spring ioc容器来管理-->
<bean name="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>

设置用户的权限信息到安全管理器/缓存管理器到安全管理器中

<!--将安全管理器交给spring ioc容器来管理-->
<bean name="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
    <!--注入自定义realm-->
    <property name="realm" ref="realm"/>
    <!--注入缓存管理器-->
    <property name="cacheManager" ref="cacheManager"/>
</bean>

使用SecurityUtils将securityManager设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);

<!--
使用SecurityUtils将securityManager设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
 -->
<!--相当于调用SecurityUtils.setSecurityManager(securityManager)-->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
    <property name="arguments" ref="securityManager"/>
</bean>

接下来把上面汇总到配置文件shiro-config.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--自定义的realm,交给spring ioc容器来管理-->
    <bean name="realm" class="com.hsy.sys.shiro.ShiroRealm"/>
    <!--缓存管理器cacheManager,交给spring ioc容器来管理-->
    <bean name="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>

    <!--将安全管理器交给spring ioc容器来管理-->
    <bean name="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
        <!--注入自定义realm-->
        <property name="realm" ref="realm"/>
        <!--注入缓存管理器-->
        <property name="cacheManager" ref="cacheManager"/>
    </bean>
    <!--
    使用SecurityUtils将securityManager设置到运行环境中
    SecurityUtils.setSecurityManager(securityManager);
     -->
    <!--相当于调用SecurityUtils.setSecurityManager(securityManager)-->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    </bean>
    <!--Shiro生命周期处理器-->
    <bean name="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>

当然别忘了spring的配置文件,上面配置文件也可以写在spring配置文件中,但是考虑代码复用,结构清晰,因此上述单独建立了一个配置文件,接下来只需在spring配置文件中引用就OK。

配置文件spring-config.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--导入shiro配置-->
    <import resource="classpath:shiro-config.xml"/>
</beans>

接下来我们进行一下测试,还是前几篇文章我们所打造的场景,现在对测试类进行如下修改

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-config.xml")
public class ShiroTest {
     
    @Autowired
    private SecurityManager securityManager;
    @Test
    public void test(){
     
        //模拟从客户端接收到用户登录输入的用户名和密码(明文)
        String name="zhangsan";
        String password="123456";
        UsernamePasswordToken token=new UsernamePasswordToken(name,password);
        Subject subject= SecurityUtils.getSubject();
        subject.login(token);
        subject.isPermitted("sys:user:list");
    }
}

测试
Shiro-菜鸟实战篇-shiro集成spring_第2张图片
可以看到我们的环境搭建已经成功,接下来就说shiro集成spring之认证、授权

shiro集成spring之认证、授权

工作准备数据库

DROP TABLE IF EXISTS `sys_resource`;
CREATE TABLE `sys_resource` (
  `resource_id` int(11) NOT NULL,
  `parent_id` int(11) NOT NULL COMMENT '父资源ID,一级资源ID为0',
  `name` varchar(50) NOT NULL,
  `url` varchar(200) default NULL,
  `permission` varchar(500) default NULL COMMENT '资源对应的权限的名称',
  `type` int(11) NOT NULL COMMENT '0:目录 1:菜单 2:按钮',
  `icon` varchar(50) default NULL,
  `ord_num` int(11) default NULL COMMENT '统计目录谁前谁后,排个序',
  `create_time` datetime default NULL,
  `update_time` datetime default NULL,
  PRIMARY KEY  (`resource_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `role_id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `remark` varchar(100) default NULL COMMENT '角色的描述',
  `dept_id` int(20) default NULL COMMENT '部门',
  `create_time` datetime default NULL,
  `update_time` datetime default NULL,
  PRIMARY KEY  (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `sys_role_resource`;
CREATE TABLE `sys_role_resource` (
  `id` int(20) NOT NULL,
  `role_id` int(20) NOT NULL,
  `resource_id` int(20) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `role_id` USING BTREE (`role_id`,`resource_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `user_id` int(11) NOT NULL,
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `salt` varchar(32) NOT NULL,
  `email` varchar(100) default NULL,
  `mobile` varchar(100) default NULL,
  `dept_id` int(20) NOT NULL,
  `status` int(11) NOT NULL default '0' COMMENT '状态 0:正常 1:禁用 2:锁定',
  `deleted` int(11) NOT NULL default '0' COMMENT '0正常 1删除',
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY  (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `id` int(20) NOT NULL,
  `user_id` int(20) NOT NULL,
  `role_id` int(20) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `user_id` USING BTREE (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

使用mybatis逆向工程造出代码

application.properties代码

jdbc.username=root
jdbc.password=123
jdbc.url=jdbc:mysql://127.0.0.1:3306/shiro_spring?useSSL=false&serverTimezone=Asia/shanghai
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.initialSize=5

#文件服务器的地址
file.server=http://localhost:8080/admin/upload
#文件上传的路径
file.location=/upload

generatorConfig.xml代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <properties resource="application.properties"/>

    <context id="mysql" targetRuntime="MyBatis3">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <!--为了防止生成的代码中有很多注释,比较难看,加入下面的配置控制-->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
        </commentGenerator>
        <!--数据库连接的信息:驱动类、连接地址、用户名、密码-->
        <jdbcConnection driverClass="${jdbc.driverClassName}"
                        connectionURL="${jdbc.url}"
                        userId="${jdbc.username}"
                        password="${jdbc.password}">

        </jdbcConnection>

        <!--targetProject:生成model类的位置-->
        <javaModelGenerator targetPackage="com.hsy.sys.model" targetProject=".\src\main\java"/>
        <!--targetProject:生成mapper映射文件的位置-->
        <javaModelGenerator targetPackage="mapper.sys" targetProject=".\src\main\resources"/>
        <!--targetProject:生成mapper接口位置-->
        <javaModelGenerator targetPackage="com.hsy.sys.mapper" targetProject=".\src\main\java" type="XMLMAPPER"/>
        <!--指定数据库表-->
        <table tableName="sys_user" domainObjectName="User"/>
        <table tableName="sys_role" domainObjectName="Role"/>
        <table tableName="sys_user_role" domainObjectName="UserRole"/>
        <table tableName="sys_resource " domainObjectName="Resource"/>
        <table tableName="sys_role_resource" domainObjectName="RoleResource"/>

    </context>

</generatorConfiguration>

接下来我们对ShiroRealm进行改造
认证

public class ShiroRealm extends AuthorizingRealm {
     

    @Autowired
    private UserMapper userMapper;

    /**
     * 登录认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
     

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        // 1.获取用户输入的用户名
        String username = token.getUsername();
        // 2.获取用户输入的密码
        String password = new String(token.getPassword());

        // 3.根据用户名去DB查询对应的用户信息
        QueryWrapper<User> param = new QueryWrapper<User>();
        param.eq("username",username);
        User user = userMapper.selectOne(param);

        if(user == null) {
     
            throw new UnknownAccountException("用户名不存在");
        }
        password = MD5Util.md5_private_salt(password,user.getSalt());

        // 两个密码的密文进行比对
        if (!user.getPassword().equals(password)) {
     
            throw new CredentialsException("密码错误");
        }
        if (user.getStatus() == 1) {
     
            throw new DisabledAccountException("账号被禁用");
        }
        if (user.getStatus() == 2) {
     
            throw new LockedAccountException("账号被锁定");
        }
        System.out.println("认证成功...");
        // 创建简单认证信息对象
        SimpleAuthenticationInfo info =
                new SimpleAuthenticationInfo(user, token.getCredentials(), getName());
        return info;
    }

进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-config.xml")
public class ShiroTest {
     
    @Autowired
    private SecurityManager securityManager;
    @Test
    public void test(){
     
        //模拟从客户端接收到用户登录输入的用户名和密码(明文)
        String name="zhangsan";
        String password="123456";
        UsernamePasswordToken token=new UsernamePasswordToken(name,password);
        Subject subject= SecurityUtils.getSubject();
        subject.login(token);

    }
}

Shiro-菜鸟实战篇-shiro集成spring_第3张图片
授权
对ShiroRealm再次进行改造

/**
 * 授权
 * 将认证通过的用户的角色和权限信息设置到对应用户主体上
 *
 * @param principals
 * @return
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
     

    User user = (User) principals.getPrimaryPrincipal();
    // 简单授权信息对象,对象中包含用户的角色和权限信息
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

    //从数据库获取当前用户的角色 通过用户名查询该用户拥有的角色名称
    Set<String> roleNameSet = userMapper.selectUserRoleNameSet(user.getUserId());
    info.addRoles(roleNameSet);

    //从数据库获取当前用户的权限 通过用户名查询该用户拥有的权限名称
    Set<String> permissionNameSet = userMapper.selectUserPermissionNameSet(user.getUserId());

    Set<String> permissions = new HashSet<String>();
    for(String name : permissionNameSet) {
     
        for(String permission : name.split(",")){
     
            permissions.add(permission);
        }
    }
    info.addStringPermissions(permissions);

    System.out.println("授权完成....");
    return info;
}

对测试类进行改造,测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-config.xml")
public class ShiroTest {
     
    @Autowired
    private SecurityManager securityManager;
    @Test
    public void test(){
     
        //模拟从客户端接收到用户登录输入的用户名和密码(明文)
        String name="zhangsan";
        String password="123456";
        UsernamePasswordToken token=new UsernamePasswordToken(name,password);
        Subject subject= SecurityUtils.getSubject();
        subject.login(token);
        System.out.println(subject.hasRole("系统管理员"));
        System.out.println(subject.hasRole("网站运维"));
        System.out.println(subject.hasRole("33333"));
        System.out.println("-------------------------");
        System.out.println(subject.isPermitted("sys:user:list"));
        System.out.println(subject.isPermitted("sys:user:update"));
        System.out.println(subject.isPermitted("sys:user:333dsf"));


    }
}

Shiro-菜鸟实战篇-shiro集成spring_第4张图片
上文链接:https://haosy.blog.csdn.net/article/details/103647880
Shiro系列专题链接:https://blog.csdn.net/qq_43518645/category_9604248.html
2019/12/22学习记录。

你可能感兴趣的:(Shiro,Spring,shiro)