欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

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>