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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 上一篇介绍了Shiro整合SpringBoot实现了登录功能,不过登录时用户信息都是写死在程序里的,也没有提供注册的功能,真实场景中肯定是不能这么干,这篇文章就是总结我们如何模拟真实场景中的注册功能,然后根据注册信息完成登录,且存入数据库的密码是经过MD5+盐+hash散列加密以后的密码。

前言:

上一篇介绍了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);
}


提供一个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.测试注册


20210327232647707.png


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


20210327232808885.png


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@#,来进行登录。

20210327233452217.png


然后,登录成功进入到了系统首页,这样我们就完成了Shiro+SpringBoot+Mybatis的整合。


三.总结



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


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
20天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
25天前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
45 5
|
26天前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
41 4
|
26天前
|
SQL Java 数据库连接
spring和Mybatis的各种查询
Spring 和 MyBatis 的结合使得数据访问层的开发变得更加简洁和高效。通过以上各种查询操作的详细讲解,我们可以看到 MyBatis 在处理简单查询、条件查询、分页查询、联合查询和动态 SQL 查询方面的强大功能。熟练掌握这些操作,可以极大提升开发效率和代码质量。
39 3
|
1月前
|
Java 数据库连接 数据库
spring和Mybatis的逆向工程
通过本文的介绍,我们了解了如何使用Spring和MyBatis进行逆向工程,包括环境配置、MyBatis Generator配置、Spring和MyBatis整合以及业务逻辑的编写。逆向工程极大地提高了开发效率,减少了重复劳动,保证了代码的一致性和可维护性。希望这篇文章能帮助你在项目中高效地使用Spring和MyBatis。
23 1
|
1月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
57 8
|
1月前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
65 9
|
1月前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
48 0
|
1月前
|
关系型数据库 MySQL Java
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
34 0
|
2月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
148 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。