SpringBoot+Shiro+mybatis整合实战
程序员文章站
2022-03-14 12:08:31
SpringBoot+Shiro+mybatis整合 1. 使用Springboot版本2.0.4 与shiro的版本 引入springboot和shiro依赖
springboot+shiro+mybatis整合
1. 使用springboot版本2.0.4 与shiro的版本
引入springboot和shiro依赖
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.smile</groupid> <artifactid>spring-demo</artifactid> <version>1.0-snapshot</version> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>2.0.4.release</version> <relativepath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceencoding>utf-8</project.build.sourceencoding> <project.reporting.outputencoding>utf-8</project.reporting.outputencoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <!--常用工具类 --> <dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-lang3</artifactid> </dependency> <!-- mysql所需的配置 --> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> </dependency> <dependency> <groupid>org.mybatis.spring.boot</groupid> <artifactid>mybatis-spring-boot-starter</artifactid> <version>1.3.2</version> </dependency> <!--阿里数据库连接池 --> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid-spring-boot-starter</artifactid> <version>1.1.10</version> </dependency> <!-- redis客户端 --> <dependency> <groupid>redis.clients</groupid> <artifactid>jedis</artifactid> </dependency> <!-- 读取资源文件所需的配置 --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-configuration-processor</artifactid> <optional>true</optional> </dependency> <!-- 引入thymeleaf模板依赖 --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-thymeleaf</artifactid> </dependency> <!-- pagehelper 分页插件 --> <dependency> <groupid>com.github.pagehelper</groupid> <artifactid>pagehelper-spring-boot-starter</artifactid> <version>1.2.5</version> </dependency> <!-- 阿里json解析器 --> <dependency> <groupid>com.alibaba</groupid> <artifactid>fastjson</artifactid> <version>1.2.47</version> </dependency> <!-- 集成shiro --> <dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-spring</artifactid> <version>1.4.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.crazycake/shiro-redis --> <dependency> <groupid>org.crazycake</groupid> <artifactid>shiro-redis</artifactid> <version>3.1.0</version> </dependency> <!-- 打印sql语句--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-jpa</artifactid> </dependency> </dependencies> </project>
2. 添加相应的配置
server: port: 8183 spring: thymeleaf: mode: html encoding: utf-8 cache: false datasource: driver-class-name: com.mysql.jdbc.driver url: jdbc:mysql://192.168.144.128:3306/spring_shiro?servertimezone=gmt&useunicode=true&characterencoding=utf-8&usessl=true #url: jdbc:mysql://localhost:3306/test?useunicode=true&characterencoding=utf8&zerodatetimebehavior=converttonull&usessl=false username: root password: root type: com.alibaba.druid.pool.druiddatasource maxactive: 20 initialsize: 1 maxwait: 60000 poolpreparedstatements: true maxpoolpreparedstatementperconnectionsize: 20 minidle: 1 timebetweenevictionrunsmillis: 60000 minevictableidletimemillis: 300000 validationquery: select 1 from dual testwhileidle: true testonborrow: false jackson: time-zone: gmt+8 date-format: yyyy-mm-dd hh:mm:ss jpa: database: mysql show-sql: true #日志级别打印 logging: level: com.example.demo: debug org.springframework: warn org.spring.springboot.dao: debug # mybatis mybatis: typealiasespackage: com.example.demo mapperlocations: classpath:mybatis/**/*mapper.xml configlocation: classpath:mybatis/mybatis-config.xml # pagehelper pagehelper: helperdialect: mysql reasonable: true supportmethodsarguments: true params: count=countsql
3. 将相关配置@bean注入容器
package com.example.demo.config; import org.apache.shiro.authc.credential.hashedcredentialsmatcher; import org.apache.shiro.mgt.securitymanager; import org.apache.shiro.session.mgt.sessionmanager; import org.apache.shiro.spring.web.shirofilterfactorybean; import org.apache.shiro.web.mgt.defaultwebsecuritymanager; import org.crazycake.shiro.rediscachemanager; import org.crazycake.shiro.redismanager; import org.crazycake.shiro.redissessiondao; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.web.servlet.config.annotation.webmvcconfigurer; import java.util.linkedhashmap; import java.util.map; /** * @时间 2019/11/25 17:17 * @作者 liutao * @描述 */ @configuration public class shiroconfig { /** * 设置过滤器 * @param securitymanager * @return */ @bean public shirofilterfactorybean shirofilterfactorybean(securitymanager securitymanager){ shirofilterfactorybean factorybean = new shirofilterfactorybean(); factorybean.setsecuritymanager(securitymanager); // 设置需要进行登录的路径api factorybean.setloginurl("/pub/need_login"); // 若是使用前后端分离,则不需要进行设置该方法 factorybean.setsuccessurl("/"); // 没有进行授权,返回的api factorybean.setunauthorizedurl("/pub/not_permit"); // 自定义过滤器 map<string, string> filtermap = new linkedhashmap<>(); // 设置退出的过滤器 filtermap.put("/logout", "logout"); // 不需要进行授权就可以进行访问,游客都可以进行访问的api filtermap.put("/pub/**", "anon"); // 需要进行授权才可以进行访问的api接口 filtermap.put("/authc/**", "authc"); // 有对应的角色才可以进行访问 filtermap.put("/admin/**", "roles[admin]"); // 设置最后的拦截器,需要进行授权才可以进行访问 filtermap.put("/**","authc"); factorybean.setfilterchaindefinitionmap(filtermap); return factorybean; } /** * 设置安全管理器 * @return */ @bean public securitymanager securitymanager(){ defaultwebsecuritymanager securitymanager = new defaultwebsecuritymanager(); securitymanager.setsessionmanager(sessionmanager()); securitymanager.setrealm(customrealm()); securitymanager.setcachemanager(cachemanage()); return securitymanager; } /** * 自定义realm * @return */ @bean public customrealm customrealm(){ customrealm customrealm = new customrealm(); // 设置密码的加密 customrealm.setcredentialsmatcher(hashedcredentialsmatcher()); return customrealm; } /** * 设置sessionid的管理器 (前后端分离,要进行获取token) * @return */ @bean public sessionmanager sessionmanager(){ customsessionmanager sessionmanager = new customsessionmanager(); // 设置sessiondao -- 里面定义了自定义sessionid sessionmanager.setsessiondao(redissessiondao()); return sessionmanager; } /** * 设置密码加密 * @return */ @bean public hashedcredentialsmatcher hashedcredentialsmatcher(){ hashedcredentialsmatcher matcher = new hashedcredentialsmatcher(); // 密码算法 matcher.sethashalgorithmname("md5"); // 加密散列次数 matcher.sethashiterations(3); return matcher; } /** * 将会话sessionid保存到redis里面,可以提高性能 * @return */ public redissessiondao redissessiondao(){ redissessiondao dao = new redissessiondao(); dao.setredismanager(redismanager()); dao.setsessionidgenerator(new customsessionidgenerator()); return dao; } /** * 接入redis数据库 * @return */ public redismanager redismanager(){ redismanager redismanager = new redismanager(); redismanager.sethost("127.0.0.1"); redismanager.setport(6379); return redismanager; } /** * 缓存管理 * @return */ @bean public rediscachemanager cachemanage(){ rediscachemanager cachemanager = new rediscachemanager(); cachemanager.setredismanager(redismanager()); // 设置过期时间,单位是秒 cachemanager.setexpire(60); return cachemanager; } /** * 加入请求头 前后端分离 * @return */ @bean public webmvcconfigurer webmvcconfigurer(){ return new webmvcconfig(); } }
4.创建customrealm类继承authorizingrealm,实现用户登录认证和权限鉴权
package com.example.demo.config; import com.example.demo.entity.user; import com.example.demo.service.userservice; import org.apache.shiro.authc.authenticationexception; import org.apache.shiro.authc.authenticationinfo; import org.apache.shiro.authc.authenticationtoken; import org.apache.shiro.authc.simpleauthenticationinfo; import org.apache.shiro.authz.authorizationinfo; import org.apache.shiro.realm.authorizingrealm; import org.apache.shiro.subject.principalcollection; import org.springframework.beans.factory.annotation.autowired; /** * @时间 2019/11/25 17:17 * @作者 liutao * @描述 */ public class customrealm extends authorizingrealm { @autowired private userservice userservice; /** * 鉴权 * @param principals * @return */ @override protected authorizationinfo dogetauthorizationinfo(principalcollection principals) { string name = (string) principals.getprimaryprincipal();
//若是使用redis和cache,获取信息转成用户对象
// user user= (user) principals.getprimaryprincipal();
return null; } /** * 登录认证 * @param token * @return * @throws authenticationexception */ @override protected authenticationinfo dogetauthenticationinfo(authenticationtoken token) throws authenticationexception { string name = (string) token.getprincipal(); user user = userservice.selectuserbyname(name); if(user == null){ return null; } // 若是加入redis和cache缓存的管理的话,需要返回 用户对象
//new simpleauthenticationinfo(user,user.getpassword(),getname());
return new simpleauthenticationinfo(name,user.getpassword(),getname()); } }
5. 创建customsessionmanager继承defaultwebsessionmanager,可以进行实现token,进行重写
package com.example.demo.config; import org.apache.shiro.web.servlet.shirohttpservletrequest; import org.apache.shiro.web.session.mgt.defaultwebsessionmanager; import org.apache.shiro.web.util.webutils; import javax.servlet.servletrequest; import javax.servlet.servletresponse; import java.io.serializable; /** * @时间 2019/11/25 17:18 * @作者 liutao * @描述 */ public class customsessionmanager extends defaultwebsessionmanager { private static final string authorization = "token"; public customsessionmanager(){ super(); } @override protected serializable getsessionid(servletrequest request, servletresponse response) { string sessionid = webutils.tohttp(request).getheader(authorization); if(sessionid != null){ request.setattribute(shirohttpservletrequest.referenced_session_id_source, shirohttpservletrequest.cookie_session_id_source); request.setattribute(shirohttpservletrequest.referenced_session_id, sessionid); //automatically mark it valid here. if it is invalid, the //onunknownsession method below will be invoked and we'll remove the attribute at that time. request.setattribute(shirohttpservletrequest.referenced_session_id_is_valid, boolean.true); return sessionid; }else{ return super.getsessionid(request,response); } } }
6. 实现自定义sessionid,创建customsessionidgenerator类实现 sessionidgenerator
package com.example.demo.config; import org.apache.shiro.session.session; import org.apache.shiro.session.mgt.eis.sessionidgenerator; import java.io.serializable; import java.util.uuid; /** * @时间 2019/11/26 16:30 * @作者 liutao * @描述 */ public class customsessionidgenerator implements sessionidgenerator { private final string prefix_sessionid = "cc0504"; public customsessionidgenerator(){ super(); } @override public serializable generateid(session session) { return prefix_sessionid + uuid.randomuuid().tostring().replaceall("-",""); } }
7.前后端分离,在header里面加入相应的数据信息
package com.example.demo.config; import org.springframework.web.servlet.config.annotation.corsregistry; import org.springframework.web.servlet.config.annotation.webmvcconfigurer; /** * @时间 2019/11/25 19:27 * @作者 liutao * @描述 */ public class webmvcconfig implements webmvcconfigurer { @override public void addcorsmappings(corsregistry registry) { registry.addmapping("/**") .allowedorigins("*") //可访问ip,ip最好从配置文件中获取, .allowedmethods("put", "delete","get","post") .allowedheaders("*") .exposedheaders("access-control-allow-headers","access-control-allow-methods","access-control-allow-origin", "access-control-max-age","x-frame-options") .allowcredentials(false).maxage(3600); } }
8. mybatis的配置
# mybatis mybatis: typealiasespackage: com.example.demo mapperlocations: classpath:mybatis/**/*mapper.xml configlocation: classpath:mybatis/mybatis-config.xml
mybatis-config.xml中的内容:
<?xml version="1.0" encoding="utf-8" ?> <!doctype configuration public "-//mybatis.org//dtd config 3.0//en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="cacheenabled" value="true" /> <!-- 全局映射器启用缓存 --> <setting name="usegeneratedkeys" value="false" /> <!-- 不允许 jdbc 支持自动生成主键 --> <setting name="defaultexecutortype" value="reuse" /> <!-- 配置默认的执行器 --> <!--<setting name="logimpl" value="slf4j" />--> <!-- 指定 mybatis 所用日志的具体实现 --> <setting name="logimpl" value="stdout_logging" /> <!-- 在控制台打印sql语句 --> <!-- <setting name="mapunderscoretocamelcase" value="true"/> 驼峰式命名 --> </settings> </configuration>
基础mapper.xml文件内容
<?xml version="1.0" encoding="utf-8" ?> <!doctype mapper public "-//mybatis.org//dtd config 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.mapper.usermapper"> <resultmap id="userresultmap" type="user"> <result column="id" property="id"/> <result column="name" property="name"/> <result column="password" property="password"/> <result column="salt" property="salt"/> </resultmap> <select id="selectallusers" resultmap="userresultmap"> select * from sys_user </select> <select id="selectuserbyname" resultmap="userresultmap"> select * from sys_user where name = #{name} </select> </mapper>