SpringBoot与Shiro的整合(单体式项目)

1.包结构

2.jar包,配置文件,类

2.1pom.xml文件配置

<?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.zy</groupId>
    <artifactId>spring-boot01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>spring-boot01</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.14.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>
        <shiro.version>1.2.3</shiro.version>
        <commons-logging.version>1.2</commons-logging.version>
        <mysql.version>5.1.45</mysql.version>
        <druid.version>1.0.21</druid.version>
        <mybatis-spring-boot.version>1.3.1</mybatis-spring-boot.version>
        <pageHelper.version>5.1.2</pageHelper.version>
        <mybatis-paginator.version>1.2.15</mybatis-paginator.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-tomcat</artifactId>
            <!--会与本地tomcat冲突
                <scope>provided</scope>
            -->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--配置mysql,Mybatis,Druid-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring-boot.version}</version>
        </dependency>
        <!--配置分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>${pageHelper.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.miemiedev</groupId>
            <artifactId>mybatis-paginator</artifactId>
            <version>${mybatis-paginator.version}</version>
        </dependency>
        <!--用于解析Html,不能与jsp的支持包同时存在-->
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>-->
        <!--添加jsp相关-->
        <!--用于解析jsp,不能与HTML的支持包同时存在-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <!--配置shiro的依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>${commons-logging.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--<plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <path>/</path>
                    <port>8081</port>
                </configuration>
            </plugin>-->
        </plugins>
    </build>


</project>

2.2spring及springmvc配置(在application.yml中)

spring:
# 配置数据库连接
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shiro
    username: root
    password: 123456
# 配置jsp的解析
  mvc:
    view:
      prefix: /WEB-INF/
      suffix: .jsp
logging:
  pattern:
    level: debug
  level:
    com.zy.controller: error
    com.zy.service: info
    com.zy.mapper: debug
  file: D:/springboot.log
# mybatis中,静态资源不发布:此处指的是resources文件夹下的文件
mybatis:
  mapper-locations: classpath:com/zy/mapper/*.xml
  config-location: classpath:sqlMappingConfig.xml
# 使用pageHelper进行分页
pagehelper:
    helperDialect: mysql
    reasonable: true
    support-methods-arguments: true
    params: count=countSql
# Shiro
shiro:
    configLocation: classpath:/ehcache.xml

2.3配置mybatis

2.3.1配置sqlMappingConfig.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="lazyLoadingEnabled" value="true"/>
        <!--关闭延迟加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!--配置分页插件pageHelper的拦截器:5.0版本之后的配置-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
</configuration>

2.3.2配置其他***Mappper.xml文件(以TbUserMapper.xml为例)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zy.mapper.TbUserMapper">

    <!--封装结果集-->
    <resultMap id="tbUserResultMap" type="com.zy.model.TbUser">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="username" property="username" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
        <result column="salt" property="salt" jdbcType="VARCHAR"/>
        <result column="status" property="status" jdbcType="VARCHAR"/>
    </resultMap>

    <!--
    根据用户名查询用户信息
    TbUser getTbUserByUserName(String username);
    -->
    <select id="getTbUserByUserName" resultMap="tbUserResultMap">
        select id,username,password,salt,status
        from tb_user
        where username = #{username}
    </select>

    <!--
     // 注册用户
    int addTbUser(TbUser tbUser);
    -->
    <insert id="addTbUser">
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select last_insert_id()
        </selectKey>
        insert into tb_user values(null,#{username},#{password},#{salt},#{status})
    </insert>

    <!--
    // 查询所有用户信息
    List<TbUser> getAllUser();
    -->
    <select id="getAllUser" resultMap="tbUserResultMap">
        select id,username,password,salt,status
        from tb_user
    </select>

    <!--
    // 删除用户信息及其关联角色信息,还需要去关联表中删除该信息
    void deleteUser(Integer id);
    -->
    <delete id="deleteUser">
        delete from tb_user where id = #{id}
    </delete>
    <delete id="deleteUserRole">
        delete from tb_user_role where user_id = #{id}
    </delete>

</mapper>

 2.4配置ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />
</ehcache>

2.5配置config包下文件

2.5.1配置Shiro主配置类(类似于ssm中的applicationContext-shiro.xml)

package com.zy.config;

import com.zy.shiro.TbUserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/login/login");
        // 设置无权限时跳转的 url;
        shiroFilterFactoryBean.setUnauthorizedUrl("/login/login");

        // 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //游客,开发权限
        //filterChainDefinitionMap.put("/guest/**", "anon");
        //用户,需要角色权限 “user”
        //filterChainDefinitionMap.put("/user/**", "roles[user]");
        //管理员,需要角色权限 “admin”
        //filterChainDefinitionMap.put("/admin/**", "roles[admin]");
        //开放登陆接口
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/layui/**", "anon");
        filterChainDefinitionMap.put("/login/logout", "logout");
        filterChainDefinitionMap.put("/login/**", "anon");
        //其余接口一律拦截
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
        filterChainDefinitionMap.put("/**", "user");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    /**
     * shiro缓存管理器;
     * 需要注入对应的其它的实体类中:
     * 1、安全管理器:securityManager
     * 可见securityManager是整个shiro的核心;
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager(){
        System.out.println("ShiroConfiguration.getEhCacheManager()");
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return cacheManager;
    }

    /**
     * 注入 securityManager
     */
    @Bean(name = "securityManager")
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(customRealm());
        //注入缓存管理器;
        securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;
        // 记住我管理器
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    /**
     * 自定义身份认证 realm;
     * <p>
     * 必须写这个类,并加上 @Bean 注解,目的是注入 CustomRealm,
     * 否则会影响 CustomRealm类 中其他类的依赖注入
     */
    // 配置自定义的权限登录器
    @Bean
    public TbUserRealm customRealm() {
        TbUserRealm tbUserRealm = new TbUserRealm();
        //告诉realm,使用credentialsMatcher加密算法类来验证密文
        tbUserRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        tbUserRealm.setCachingEnabled(true);
        return tbUserRealm;
    }
    /**
     * 凭证匹配器
     * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * )
     * 可以扩展凭证匹配器,实现 输入密码错误次数后锁定等功能,下一次
     * @return
     */
    @Bean(name="credentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1);//散列的次数,比如散列两次,相当于 md5(md5(""));
        //storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
        //hashedCredentialsMatcher.setStoredCredentialsHexEncoded(false);

        return hashedCredentialsMatcher;
    }

    /**
     * cookie对象;
     * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
        //System.out.println("ShiroConfiguration.rememberMeCookie()");
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间 ,单位秒;-->
        simpleCookie.setMaxAge(604800);
        return simpleCookie;
    }

    /**
     * cookie管理对象;
     * rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        //System.out.println("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        return cookieRememberMeManager;
    }

    /*开启切面支持,spring拦截支持
    * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类
    * */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }



    //把shiro生命周期交给spring boot管理
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }


    /**
     *
     * 添加ShiroDialect 为了在thymeleaf里使用shiro的标签的bean
     * @return
     * 此处不用
        @Bean(name = "shiroDialect")
        public ShiroDialect shiroDialect(){
            return new ShiroDialect();
        }
     */
}

2.5.2配置静态资源类

package com.zy.config;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class StaticResourceConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /*配置js,css等*/
        registry.addResourceHandler("/js/**").addResourceLocations("WEB-INF/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("WEB-INF/css/");
        registry.addResourceHandler("/fonts/**").addResourceLocations("WEB-INF/fonts/");
        registry.addResourceHandler("/images/**").addResourceLocations("WEB-INF/images/");
        registry.addResourceHandler("/layui/**").addResourceLocations("WEB-INF/layui/");
        //registry.addResourceHandler("/error/**").addResourceLocations("WEB-INF/error/");
        super.addResourceHandlers(registry);
    }

    //统一页码处理配置
    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                //ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html");
                ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/WEB-INF/error/404.jsp");
                ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/WEB-INF/error/500.jsp");

                container.addErrorPages( error404Page, error500Page);
            }
        };
    }

}

2.6配置springboot的启动类

package com.zy;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
/*配置事务的注解,同时也需要在service层方法上添加注解*/
@EnableTransactionManagement
/*整合mybatis*/
@MapperScan("com.zy.mapper")
public class SpringBoot01Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot01Application.class, args);
    }
}

2.8其他mapper层,service层,controller层配置详见https://www.cnblogs.com/psy-code/p/9457947.html

猜你喜欢

转载自www.cnblogs.com/psy-code/p/9458014.html
今日推荐