直接上代碼
pom文件
<?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.chaoqi</groupId>
<artifactId>springboot_mybatisplus</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot_mybatisplus</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/>
</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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- reids -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--添加jsp依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- SpringBoot - MyBatis 逆向工程 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MyBatis 通用 Mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.4</version>
</dependency>
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<!-- shiro+redis緩存插件 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.2.1-RELEASE</version>
</dependency>
<!-- fastjson阿里巴巴jSON處理器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.13</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-security</artifactId>-->
<!--</dependency>-->
<!--工具類-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
</dependencies>
</project>
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 沒有登陸的用戶只能訪問登陸頁面
shiroFilterFactoryBean.setLoginUrl("/auth/login");
// 登錄成功後要跳轉的鏈接
shiroFilterFactoryBean.setSuccessUrl("/auth/index");
// 未授權界面; ----這個配置了沒卵用,具體原因想深入瞭解的可以自行百度
//shiroFilterFactoryBean.setUnauthorizedUrl("/auth/403");
//自定義攔截器
Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
//限制同一帳號同時在線的個數。
filtersMap.put("kickout", kickoutSessionControlFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
// 權限控制map.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/auth/login", "anon");
filterChainDefinitionMap.put("/auth/logout", "logout");
filterChainDefinitionMap.put("/auth/kickout", "anon");
filterChainDefinitionMap.put("/**", "authc,kickout");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 設置realm.
securityManager.setRealm(myShiroRealm());
// 自定義緩存實現 使用redis
securityManager.setCacheManager(cacheManager());
// 自定義session管理 使用redis
securityManager.setSessionManager(sessionManager());
return securityManager;
}
/**
* 身份認證realm; (這個需要自己寫,賬號密碼校驗;權限等)
*
* @return
*/
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
/**
* cacheManager 緩存 redis實現
* 使用的是shiro-redis開源插件
*
* @return
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManagernew());
return redisCacheManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis開源插件
*
* @return
*/
public RedisManagerNew redisManagernew() {
RedisManagerNew redisManager = new RedisManagerNew();
redisManager.setHost("127.0.0.1");
redisManager.setPort(6379);
redisManager.setExpire(1800);// 配置緩存過期時間
redisManager.setTimeout(2000);
redisManager.setDatabase(1);
redisManager.setPassword("RmUnifiedAntiFraud");
return redisManager;
}
/**
* Session Manager
* 使用的是shiro-redis開源插件
*/
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
return sessionManager;
}
/**
* RedisSessionDAO shiro sessionDao層的實現 通過redis
* 使用的是shiro-redis開源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
/**
* 限制同一賬號登錄同時登錄人數控制
*
* @return
*/
@Bean
public KickoutSessionControlFilter kickoutSessionControlFilter() {
KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
kickoutSessionControlFilter.setCacheManager(cacheManager());
kickoutSessionControlFilter.setSessionManager(sessionManager());
kickoutSessionControlFilter.setKickoutAfter(false);
kickoutSessionControlFilter.setMaxSession(1);
kickoutSessionControlFilter.setKickoutUrl("/auth/kickout");
return kickoutSessionControlFilter;
}
/***
* 授權所用配置
*
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
/***
* 使授權註解起作用不如不想配置可以在pom文件中加入
* <dependency>
*<groupId>org.springframework.boot</groupId>
*<artifactId>spring-boot-starter-aop</artifactId>
*</dependency>
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Shiro生命週期處理器
*
*/
@Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
}
因爲RedisManager沒有設置制定數據庫,所以對RedisManager重寫爲RedisManagerNew
import org.crazycake.shiro.RedisManager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Set;
public class RedisManagerNew extends RedisManager {
private String host = "127.0.0.1";
private int port = 6379;
private int expire = 0;
private int timeout = 0;
private String password = "";
private int database = 1;
private static JedisPool jedisPool = null;
public RedisManagerNew() {
}
@Override
public void init() {
if (jedisPool == null) {
if (this.password != null && !"".equals(this.password)) {
jedisPool = new JedisPool(new JedisPoolConfig(), this.host, this.port, this.timeout, this.password,this.database);
} else if (this.timeout != 0) {
jedisPool = new JedisPool(new JedisPoolConfig(), this.host, this.port, this.timeout);
} else {
jedisPool = new JedisPool(new JedisPoolConfig(), this.host, this.port);
}
}
}
@Override
public byte[] get(byte[] key) {
byte[] value = null;
Jedis jedis = (Jedis)jedisPool.getResource();
try {
value = jedis.get(key);
} finally {
jedisPool.returnResource(jedis);
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value) {
Jedis jedis = (Jedis)jedisPool.getResource();
try {
jedis.set(key, value);
if (this.expire != 0) {
jedis.expire(key, this.expire);
}
} finally {
jedisPool.returnResource(jedis);
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value, int expire) {
Jedis jedis = (Jedis)jedisPool.getResource();
try {
jedis.set(key, value);
if (expire != 0) {
jedis.expire(key, expire);
}
} finally {
jedisPool.returnResource(jedis);
}
return value;
}
@Override
public void del(byte[] key) {
Jedis jedis = (Jedis)jedisPool.getResource();
try {
jedis.del(key);
} finally {
jedisPool.returnResource(jedis);
}
}
@Override
public void flushDB() {
Jedis jedis = (Jedis)jedisPool.getResource();
try {
jedis.flushDB();
} finally {
jedisPool.returnResource(jedis);
}
}
@Override
public Long dbSize() {
Long dbSize = 0L;
Jedis jedis = (Jedis)jedisPool.getResource();
try {
dbSize = jedis.dbSize();
} finally {
jedisPool.returnResource(jedis);
}
return dbSize;
}
@Override
public Set<byte[]> keys(String pattern) {
Set<byte[]> keys = null;
Jedis jedis = (Jedis)jedisPool.getResource();
try {
keys = jedis.keys(pattern.getBytes());
} finally {
jedisPool.returnResource(jedis);
}
return keys;
}
@Override
public String getHost() {
return this.host;
}
@Override
public void setHost(String host) {
this.host = host;
}
@Override
public int getPort() {
return this.port;
}
@Override
public void setPort(int port) {
this.port = port;
}
@Override
public int getExpire() {
return this.expire;
}
@Override
public void setExpire(int expire) {
this.expire = expire;
}
@Override
public int getTimeout() {
return this.timeout;
}
@Override
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public void setPassword(String password) {
this.password = password;
}
public int getDatabase() {
return database;
}
public void setDatabase(int database) {
this.database = database;
}
}
application.yml
server:
port: 8080
spring:
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
datasource:
url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&useUnicode=true&useSSL=false
username: root
password: 123123
driver-class-name: com.mysql.jdbc.Driver
redis:
host: 127.0.0.1
port: 6379
database: 1
password: RmUnifiedAntiFraud
jedis:
pool:
max-idle: 10
min-idle: 0
max-active: 200
max-wait: -1
timeout: 1000
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.chaoqi.springboot_mybatisplus.domain
設置ShiroRealm
package com.chaoqi.springboot_shiro_redis.secutity;
import com.chaoqi.springboot_shiro_redis.service.SysRoleService;
import com.chaoqi.springboot_shiro_redis.service.UserService;
import com.chaoqi.springboot_shiro_redis.dao.domain.SysUser;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
public class MyShiroRealm extends AuthorizingRealm {
private static org.slf4j.Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
//如果項目中用到了事物,@Autowired註解會使事物失效,可以自己用get方法獲取值
@Autowired
private SysRoleService roleService;
@Autowired
private UserService userService;
/**
* 認證信息.(身份驗證) : Authentication 是用來驗證用戶身份
*
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
logger.info("---------------- 執行 Shiro 憑證認證 ----------------------");
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String name = token.getUsername();
String password = String.valueOf(token.getPassword());
SysUser user = new SysUser();
user.setUserName(name);
user.setPassWord(password);
// 從數據庫獲取對應用戶名密碼的用戶
SysUser userList = userService.getUser(user);
if (userList != null) {
// 用戶爲禁用狀態
if (userList.getUserEnable() != 1) {
throw new DisabledAccountException();
}
logger.info("---------------- Shiro 憑證認證成功 ----------------------");
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userList, //用戶
userList.getPassWord(), //密碼
getName() //realm name
);
return authenticationInfo;
}
throw new UnknownAccountException();
}
/**
* 授權
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("---------------- 執行 Shiro 權限獲取 ---------------------");
Object principal = principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
if (principal instanceof SysUser) {
SysUser userLogin = (SysUser) principal;
Set<String> roles = roleService.findRoleNameByUserId(userLogin.getId());
authorizationInfo.addRoles(roles);
Set<String> permissions = userService.findPermissionsByUserId(userLogin.getId());
authorizationInfo.addStringPermissions(permissions);
}
logger.info("---- 獲取到以下權限 ----");
logger.info(authorizationInfo.getStringPermissions().toString());
logger.info("---------------- Shiro 權限獲取成功 ----------------------");
return authorizationInfo;
}
}
以上配置爲shiro與redis的整合
以下爲springboot與redis的整合
package com.chaoqi.springboot_shiro_redis.config;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
public class RedisConverter implements RedisSerializer<Object> {
private Converter<Object, byte[]> serializer = new SerializingConverter();//序列化器
private Converter<byte[], Object> deserializer = new DeserializingConverter();//反序列化器
@Override
public byte[] serialize(Object o) throws SerializationException {//將對象序列化成字節數組
if (o == null){
return new byte[0];
}
try {
return serializer.convert(o);
} catch (Exception e) {
e.printStackTrace();
return new byte[0];
}
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {//將字節數組反序列化成對象
if (bytes == null || bytes.length == 0){
return null;
}
try {
return deserializer.convert(bytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.chaoqi.springboot_shiro_redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
/**
* @param redisConnectionFactory
* @return 自定義redisTemplate,自帶的bean沒有序列化器
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());//設置key的序列化器
redisTemplate.setValueSerializer(new RedisConverter());//設置值的序列化器
return redisTemplate;
}
}
調用RedisTemplate即可