SpringBoot+Shiro+mybatis整合 1. 使用Springboot版本2.0.4 與shiro的版本 引入springboot和shiro依賴 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.a ...
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>