1. 程式人生 > >SpringBoot整合Shiro+mybatis-plus

SpringBoot整合Shiro+mybatis-plus


原始碼地址: link

一、新增依賴

<?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.joecy</groupId> <artifactId>springboot_mybatis-plus_shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot_mybatis-plus_shiro</name> <description>Spring Boot整合Mybitis Plus和Shiro小Demo</
description
>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties
>
<java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version> <mybatisplus.version>2.1.4</mybatisplus.version> <shiro-spring.version>1.3.2</shiro-spring.version> <druid.version>1.0.18</druid.version> <lombok.version>1.18.2</lombok.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--沒有此依賴shiro註解許可權會失效--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!--lombok外掛使用依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <!--mybatis plus依賴--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>${mybatisplus-spring-boot-starter.version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>${mybatisplus.version}</version> </dependency> <!--資料來源相關--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--shiro依賴--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro-spring.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--熱部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> </dependencies> </project>

二、application.properties配置檔案

server.port=8080
# 資料庫訪問配置
# 主資料來源,預設的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus_shiro_test?Unicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456

# 下面為連線池的補充設定,應用到上面所有資料來源中
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置獲取連線等待超時的時間
spring.datasource.maxWait=60000
# 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一個連線在池中最小生存的時間,單位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 開啟PSCache,並且指定每個連線上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置監控統計攔截的filters,去掉後監控介面sql無法統計,'wall'用於防火牆
spring.datasource.filters=stat,wall,log4j
# 通過connectProperties屬性來開啟mergeSql功能;慢SQL記錄
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合併多個DruidDataSource的監控資料
#spring.datasource.useGlobalDataSourceStat=true

#整合Freemark
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.allow-session-override=true
#Mybatis配置
mybatis-plus.mapper-locations=classpath:mappers/*.xml
#mybatis-plus的model包
mybatis-plus.typeAliasesPackage=com.joecy.entity
#global-config:
#主鍵型別  0:"資料庫ID自增", 1:"使用者輸入ID",2:"全域性唯一ID (數字型別唯一ID)", 3:"全域性唯一ID UUID";
#id-type: 2
mybatis-plus.global-config.id-type=0
#駝峰式命名對映
mybatis-plus.global-config.db-column-underline=true

三、mybatis-plus相關

1 新建資料庫表對應的model,以SecUser為例

/**
 * 使用者表
 * 需要繼承mybatis-plus的Model<>抽象類
 */
@Data
public class SecUser extends Model<SecUser> {

    //指定id
    @TableId
    private Integer id;
    private String username;
    private String password;
    @TableField(exist = false)
    private List<SecRole> roles;

    //實現預設id方法
    //若一個表沒有id 直接return null即可
    @Override
    protected Serializable pkVal() {
        return this.id;
    }
}

2 建立SecUser對應Mapper SecUserMapper

//必須新增mybatis的@Mapper註解
@Mapper
public interface SecUserMapper extends BaseMapper<SecUser> {
}

至此該model就可以正常使用了,具體使用方法很簡單,參照mybatis-plus官網:link

四、現在開始Shiro配置

1 建立MyShiroRealm

//實現AuthorizingRealm介面使用者使用者認證
public class MyShiroRealm extends AuthorizingRealm {

    //角色許可權和對應許可權新增
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //新增角色和許可權
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        System.out.println(principalCollection.getPrimaryPrincipal());
        SecUser user= (SecUser) principalCollection.getPrimaryPrincipal();
        //儲存所有角色名
        Set<String> allRoles = new HashSet<>();
        //儲存所有許可權名
        Set<String> allPermissions = new HashSet<>();
        //查詢對應角色
        List<SecUserRole> secUserRoles = new SecUserRole().selectList(new EntityWrapper().eq("user_id", user.getId()));
        for (SecUserRole userRole:secUserRoles) {
            SecRole role = new SecRole();
            role.setId(userRole.getRoleId());
            role = role.selectById();
            allRoles.add(role.getName());

            //查詢所有許可權
            List<SecPermission> permissions = new ArrayList<>();
            List<SecRolePermission> rolePermissions = new SecRolePermission().selectList(new EntityWrapper().eq("role_id", role.getId()));
            for (SecRolePermission rolePermission:rolePermissions) {
                SecPermission permission = new SecPermission();
                permission.setId(rolePermission.getPermissionId());
                permission = permission.selectById();
                allPermissions.add(permission.getName());
            }
        }
        //新增角色
        simpleAuthorizationInfo.addRoles(allRoles);
        simpleAuthorizationInfo.addStringPermissions(allPermissions);


        System.out.println(user);

        return simpleAuthorizationInfo;
    }

    //使用者認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 1、登入認證的方法需要先執行,需要用他來判斷登入的使用者資訊是否合法
        String username = (String) token.getPrincipal();    // 取得使用者名稱
        // 需要通過使用者名稱取得使用者的完整資訊,利用業務層操作
        SecUser user = null;
        try {
            user = new SecUser().selectOne(new EntityWrapper().eq("username",username));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (user == null) {
            throw new UnknownAccountException("該使用者名稱稱不存在!");
        } else {    // 進行密碼的驗證處理
            String password =new String((char[]) token.getCredentials());
            // 將資料庫中的密碼與輸入的密碼進行比較,這樣就可以確定當前使用者是否可以正常登入
            if (user.getPassword().equals(password)) {    // 密碼正確

                AuthenticationInfo auth = new SimpleAuthenticationInfo(user, password, "memberRealm");
                return auth;
            } else {
                throw new IncorrectCredentialsException("密碼錯誤!");
            }
        }
    }
}

2 建立Shiro配置類ShiroConfig

@Configuration
public class ShiroConfig {

    //將自己的驗證方式加入容器
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }

    //許可權管理,配置主要是Realm的管理認證
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    //Filter工廠,設定對應的過濾條件和跳轉條件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必須設定 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 如果不設定預設會自動尋找Web工程根目錄下的"/login.jsp"頁面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登入成功後要跳轉的連結
        shiroFilterFactoryBean.setSuccessUrl("/index");


        // 許可權控制map.
        LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
        filterChainDefinitionMap.put("/css/**", "anon"); //表示可以匿名訪問
        filterChainDefinitionMap.put("/js/**", "anon"); //表示可以匿名訪問
        filterChainDefinitionMap.put("/img/**", "anon"); //表示可以匿名訪問
        filterChainDefinitionMap.put("/font/**", "anon"); //表示可以匿名訪問
        filterChainDefinitionMap.put("/images/**", "anon"); //表示可以匿名訪問
        filterChainDefinitionMap.put("/login", "anon"); //表示可以匿名訪問
        filterChainDefinitionMap.put("/user_login", "anon");
        filterChainDefinitionMap.put("/logout*","logout");
        filterChainDefinitionMap.put("/error","anon");
        filterChainDefinitionMap.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    //加入註解的使用,不加入這個註解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        System.out.println("開啟了shiro註解功能");
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authoriz