shiro学习基础(二)之springBoot例子


前言

这是shiro的初期学习笔记,如有错误,欢迎各位大佬指出错误!

以下教程来源

how2j学习教程

在springBoot中使用shiro

创建项目这些步骤就不赘述了;项目创建好之后,在src下添加一个webapp目录,并且添加一个WEB-INF目录,形成如下项目结构:
在这里插入图片描述
然后在项目结构中将webapp作为项目资源,如下:
在这里插入图片描述
ps:
如果不自定义项目资源上面的步骤都可以省略。。。。

然后在application.properties中添加项目配置,如下:

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

mybatis.mapper-locations=classpath:mapper/ *.xml 

mybatis.type-aliases-package=com.drillsb.demo.pojo

添加依赖,如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.drillsb</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <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>

        <!--        Servlet的依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <!--        tomcat的支持-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>


        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>

        <!-- mybatis 逆向工程 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>

        <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- shiro-web -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

<!--                资源路径-->
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

注意:添加的是shiro的依赖如下:

 <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- shiro-web -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.3.2</version>
        </dependency>

还有就是是自定义项目资源路径,所以在pom.xml中也必须要配置,如下:

 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

<!--                资源路径-->
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

之后就是项目的各个页面以及类,直接在
shiro学习基础(二)之web例子中的ssm中是一样的,copy过来就可以了,形成的项目结构如下:

在这里插入图片描述

需要改变的地方

替代applicationContext-shiro文件

替代在ssm中的applicationContext-shiro的配置文件作用,我们需要创建一个配置文件类,如下:

package com.drillsb.demo.shiro;

import com.drillsb.demo.filter.UrlPathMatchingFilter;
import com.drillsb.demo.realm.DatabaseRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
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.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration//表示这是个配置文件类
public class ShiroConfiguration {
    /*
    * @Bean表示该方法的返回值归spring管理
    * */
    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是会报错的,因为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     *
     Filter Chain定义说明
     1、一个URL可以配置多个Filter,使用逗号分隔
     2、当设置多个过滤器时,全部验证通过,才视为通过
     3、部分过滤器可指定参数,如perms,roles
     *
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        //自定义拦截器
        Map<String, Filter> customisedFilter = new HashMap<>();
        customisedFilter.put("url", getURLPathMatchingFilter());

        //配置映射关系
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/index", "anon");
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/config/**", "anon");
        filterChainDefinitionMap.put("/doLogout", "logout");;
        filterChainDefinitionMap.put("/**", "url");
        shiroFilterFactoryBean.setFilters(customisedFilter);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /*
    * 需要注意一点,URLPathMatchingFilter 并没有用@Bean管理起来。
    * 原因是Shiro的bug, 这个也是过滤器,ShiroFilterFactoryBean 也是过滤器,
    * 当他们都出现的时候,默认的什么anno,authc,logout过滤器就失效了。所以不能把他声明为@Bean。
     * */
    public UrlPathMatchingFilter getURLPathMatchingFilter() {
        return new UrlPathMatchingFilter();
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(getDatabaseRealm());
        return securityManager;
    }

    @Bean
    public DatabaseRealm getDatabaseRealm(){
        DatabaseRealm myShiroRealm=new DatabaseRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }

    /**
     * 凭证匹配器
     * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * )
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));

        return hashedCredentialsMatcher;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}

在上面配置的UrlPathMatchingFilter类,并没有在spring的管理中,也就是说当我们注入对象给予这个类的时候,也无法生效;

为了解决这个问题,需要手动将对象注入到这个类中;

所以需要在util包下创建一个类SpringContextUtils,该类继承了ApplicationContextAware,关于这个类引用博文Spring中的ApplicationContextAware接口的使用中提到了,继承了这个类能够轻松的获取所有的spring管理的bean,
SpringContextUtils如下:

package com.drillsb.demo.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/*
在ShiroConfiguration中配置URLPathMatchingFilter 没有被声明为@Bean
也就是无法在spring中管理这个拦截器类

同样也无法在该URLPathMatchingFilter类中注入PermissionService
* 在业务上URLPathMatchingFilter 里面又必须使用PermissionService类

这个类就是解决这个问题存在的
* */
@Component
public class SpringContextUtils implements ApplicationContextAware {//是你
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
//        把ApplicationContext上下文对象给我们创建的类
        SpringContextUtils.context=applicationContext;
    }
//    获取上下文对象
    public static ApplicationContext getContext() {
        return context;
    }

}

然后在UrlPathMatchingFilter类中,就可以手动将要注入到该类的属性注入了,如下:

package com.drillsb.demo.filter;


import com.drillsb.demo.service.PermissionService;
import com.drillsb.demo.util.SpringContextUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.Set;

public class UrlPathMatchingFilter extends PathMatchingFilter {
    @Autowired
    PermissionService permissionService;

    @Override
    protected boolean onPreHandle(ServletRequest request,
                                  ServletResponse response,
                                  Object mappedValue) throws Exception {
//        System.out.println("话说这个到底是有没有被spring管理: "+permissionService);
        /*
        * 这一步是必要的,不然就是null
        * */
        if(null==permissionService){
            permissionService = SpringContextUtils.getContext().getBean(PermissionService.class);
        }
//        获取访问的地址
        String requestURL=getPathWithinApplication(request);
//        System.out.println("这个东西是啥?: "+requestURL);

        Subject subject = SecurityUtils.getSubject();

//       如果没有登录就跳转到登录页面
        if(!subject.isAuthenticated()){
            WebUtils.issueRedirect(request, response, "/login");
            return false;
        }
        boolean needInterceptor = permissionService.needInterceptor(requestURL);
//        如果访问的路径在权限表中不存在,那么就放行
        if(!needInterceptor){
            return true;
        }else{
            boolean hasPermission=false;
//            获取用户名
            String userName = subject.getPrincipal().toString();
//            通过用户名获取该用户拥有的权限url集合
            Set<String> permissionUrls = permissionService.listPermissionURLs(userName);
            for (String userPermissionUrl : permissionUrls) {
//                如果该用户权限url集合中包含了访问的路径url
                if(userPermissionUrl.equals(requestURL)){
                    hasPermission=true;
                    break;
                }
            }
            if (hasPermission){
                return true;
            } else {
                UnauthorizedException ex = new UnauthorizedException("当前用户没有访问路径 " + requestURL + " 的权限");

                subject.getSession().setAttribute("ex", ex);

                WebUtils.issueRedirect(request, response, "/unauthorized");
                return false;
            }
        }

    }
}

修改copy过来的xml文件

因为mapper类中的xml文件是直接copy在ssm项目中的,所以需要修改其xml中的类型,将所有的包名都改为自己项目所在的包名,不然就会报错

修改jsp文件的静态资源引入

分为两种,一种是不需要访问以及目录的引入,根据在pom.xml文件配置的,引入静态文件路径写法如下:
在这里插入图片描述
另一种是在请求路径中添加了一级目录的,如下引入写法:
在这里插入图片描述
其它的没啥变化,运行主程序文件,如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值