2021年你还不会Shiro?----7.Shiro整合SpringBoot整合Mybatis+Mysql


前言:
上一篇介绍了Shiro整合SpringBoot实现了登录功能,不过登录时用户信息都是写死在程序里的,也没有提供注册的功能,真实场景中肯定是不能这么干,这篇文章就是总结我们如何模拟真实场景中的注册功能,然后根据注册信息完成登录,且存入数据库的密码是经过MD5+盐+hash散列加密以后的密码。

一.整合过程

上一篇文章已经介绍了Shiro整合SpingBoot的过程,这一篇就接着上一篇的内容去整合Mybatis+Mysql了,若是没有数据库,可以根据下面这篇先去装上一个mysql的数据库。看完女朋友都能装数据库的教程

1.导入Mybatis与Mysql相关的依赖

如下所示,首先我们需要引入Mybatis的启动器、Mysql的驱动类、以及druid的数据源。

        <!--引入mybatis的依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <!--引入连接mysql的驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!--引入数据源连接池依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.19</version>
        </dependency>

2.配置application.properties文件

我们需要配置数据库的参数和Mybatis的别名以及mapper文件路径,如下所示

# 数据库相关配置
#连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#驱动类
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#数据库地址
spring.datasource.url=jdbc:mysql://192.168.150.130:3306/shiro?characterEncoding=UTF-8&useSSL=false
#数据库用户名与密码
spring.datasource.username=root
spring.datasource.password=super

# mybatis 别名配置,配置该参数mapper中才认识自定义类型
mybatis.type-aliases-package=com.example.demo5.entry
# 配置了该参数才能找到我们写mapper文件
mybatis.mapper-locations=classpath:com/example/demo5/mapper/*.xml

3.提供Service接口及其实现类,以及dao接口

我们需要为用户信息提供服务层接口以及数据处理层的接口,如下:

  1. Service层接口
    服务层接口,两个方法就够了,一个用户注册时插入到表中,一个用户登录时查询用户信息。

    public interface ShiroUserService {
          
          
        void insertUser(ShiroUser shiroUser);
        ShiroUser queryUser(String username);
    }
    
  2. Service层实现类

    @Service
    @Transactional
    public class ShiroUserServiceImpl implements ShiroUserService {
          
          
    
        @Autowired
        private ShiroUserDao shiroUserDao;
    
        @Override
        public void insertUser(ShiroUser shiroUser) {
          
          
            //使用MD5+盐+hash散列进行对密码加密
            String salt = SaltUttil.getSalt(10);
            Md5Hash md5Hash = new Md5Hash(shiroUser.getPassword(),salt ,2048);
            shiroUser.setPassword(md5Hash.toString());
            shiroUser.setSalt(salt);
            shiroUserDao.insertUser(shiroUser);
        }
    
        @Override
        public ShiroUser queryUser(String username) {
          
          
            ShiroUser shiroUser = shiroUserDao.queryUser(username);
            return shiroUser;
        }
    }
    
  3. dao接口
    我们需要为dao接口提供一个Mapper注解,或者在启动类上加入MapperScan注解也可以。两者选其一即可。

    //@Mapper
    public interface ShiroUserDao {
          
          
       void insertUser(ShiroUser shiroUser);
       ShiroUser queryUser(String username);
    }
    
  4. 提供一个Salt的生成工具类

    public class SaltUttil {
          
          
     public static String getSalt(int n){
          
          
         char[] chars  = "ABCDEFGHIJKLMN0PQRSTUVWXYZabcdefghijklmn0pqrstuvwxyz0123456789~!@#$%^&*;'.,".toCharArray();
         StringBuilder stringBuilder  = new StringBuilder();
         for(int i=0;i<n;i++){
          
          
             double random = Math.random()*75;
             char ch = chars[(int)(Math.random()*75)];
             stringBuilder.append(ch);
         }
         return stringBuilder.toString();
     }
    
    

4.根据dao方法实现mapper.xml文件

每个dao方法都要映射到一个mapper文件内的一段sql。我们前面使用的Mapper标签就是为了根据mapper文件中的sql自动生成dao的实现类。我们首先需要在resoures文件夹下创建一个目录,目录名随意,这里需要与application.properties中配置的mapper路径保持一致。创建目录时,若是多级目录注意不能使用点隔开,应使用/隔开。
mapper.xml文件内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo5.dao.ShiroUserDao">

    <sql id="shiro_user_fields">
      oid,username,password,salt
    </sql>

    <insert id="insertUser" parameterType="ShiroUser" useGeneratedKeys="true" keyProperty="oid">
        insert into shiro_user values (#{
    
    oid},#{
    
    username},#{
    
    password},#{
    
    salt})
    </insert>

    <select id="queryUser" parameterType="java.lang.String" resultType="ShiroUser">
        select
        <include refid="shiro_user_fields"/>
        from shiro_user where 1=1
        <if test="username != null and username != ''">
          and username = #{
    
    username}
        </if>
    </select>
</mapper>

这也是一个标准的mapper.xml文件的模板,可以当做模板使用,该文件需要注意的就是,命名空间需要是dao的全限定名。

5.整合完成

到这里其实就整合完成了。如果整合过程中碰到任何问题请参考这篇文章,SpringBoot整合MyBatis,service层中的insert方法对应的就是注册功能,可以看到调用dao方法时,传入的是MD5+盐+hash散列处理后的密码,这样我们在数据库存储的就是加密后的密码了。

二.实现注册与登录

完整的登录肯定是从注册开始,注册就必须得先有个注册页面。

1.提供注册页面。

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>注册</title>
    <style type="text/css">
        *{
    
    margin: 0;padding: 0;}
        form{
    
    margin: 0 auto;padding:15px; width: 300px;height:300px;text-align: center;}
        #submit{
    
    padding: 10px}
        #submit input{
    
    width: 50px;height: 24px;}
    </style>
</head>
<body>
    <h1>注册页</h1>

    <form action="${pageContext.request.contextPath}/user/register" method="post">
        用户名:<input type="text" name ="username"/><br/>
        密 码 :<input type="text" name ="password"/><br/>
        <input type="submit" value="立即注册"><br/>
    </form>
</body>
</html>

2.提供登录接口

然后需要提供一个接口register供调用,存储用户信息,register接口如下,这里我们直接调用Service层接口即可。

    @PostMapping("/register")
    public String register(ShiroUser shiroUser){
    
    
        try {
    
    
            shiroUserService.insertUser(shiroUser);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return "redirect:/register.jsp";
        }
        return "redirect:/login.jsp";
    }

这样我们就可以完成整个注册的流程了。

3.测试注册

在这里插入图片描述
点击立即注册后,我们查看数据库中有无数据,然后我们发现注册正常,数据以及有了,这证明我们写的注册功能没有问题。
在这里插入图片描述

4.Realm中查询数据库用户信息

既然注册成功了,我们就需要为登录做准备了,我们知道认证予授权的数据均是来自Realm,那么我们的Realm自然就需要调用Service的方法来查询数据库信息了。实现如下:

public class FirstRealm extends AuthorizingRealm {
    
    

    @Autowired
    ShiroUserService shiroUserService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)authenticationToken;
        ShiroUser shiroUser = shiroUserService.queryUser(usernamePasswordToken.getUsername());
        if(shiroUser!=null){
    
    
            return new SimpleAuthenticationInfo(shiroUser.getUsername(),shiroUser.getPassword(),ByteSource.Util.bytes(shiroUser.getSalt()),this.getName());
        }
        return null;
    }
}

5.为自定义Realm设置密码匹配器

因为使用了MD5+盐+hash散列的方式进行加密,那么我们需要为Realm重新设置密码匹配器,并告诉他散列的次数。

@Configuration
public class ShiroConfig {
    
    

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
    
    
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        Map<String,String> map = new HashMap<>();
        map.put("/user/*","anon");//表示该资源无需认证授权,无需授权的应该写在上面
        map.put("/user/logout","anon");//表示该资源无需认证授权
        map.put("/register.jsp","anon");//表示该资源无需认证授权
        map.put("/test","anon");//表示该资源无需认证授权
        map.put("/login.jsp","anon");//表示该资源无需认证授权,此处不写是不能正常访问到登录页面的,
        //但是看的课程上是可以访问到,并且无其他配置,这块如果不加,我这里访问不到登录页,会陷入循环的重定向。
        map.put("/**","authc");//表示所有资源都需要经过认证授权
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        //设置授权失败返回的页面
        shiroFilterFactoryBean.setLoginUrl("login.jsp");//这也是默认值
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(FirstRealm firstReaml){
    
    
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(firstReaml);
        return defaultWebSecurityManager;
    }

    @Bean
    public FirstRealm getRealm(){
    
    
        FirstRealm firstRealm = new FirstRealm();
        Md5CredentialsMatcher md5CredentialsMatcher = new Md5CredentialsMatcher();
        md5CredentialsMatcher.setHashIterations(2048);
        firstRealm.setCredentialsMatcher(md5CredentialsMatcher);
        return firstRealm;
    }
}

这样我们就完成了登录所需要的所有条件。

6.测试登录

我们使用我们刚刚注册地秦始皇:qaz1231@#,来进行登录。
在这里插入图片描述
然后,登录成功进入到了系统首页,这样我们就完成了Shiro+SpringBoot+Mybatis的整合。

三.总结

前面几篇文章里已经介绍过了MD5+盐+hash散列的过程,所以这篇文章其实旨在整合的过程,代码其实都是旧代码,只是应用在了一个完整的流程中。并没有太多的新意,总结下这个过程,以防忘记,若是能帮助到看到此处的你深感荣幸。

猜你喜欢

转载自blog.csdn.net/m0_46897923/article/details/115186331