zoukankan      html  css  js  c++  java
  • Springboot+Shiro+Mybatis+mysql

    一 、shiro框架

    Shiro是Apache 的一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。Shiro 主要分为两个部分就是认证和授权两部分


    1.Subject代表了当前用户的安全操作


    2.SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。


    3.Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。


    4.Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

     

    5.Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。


    6.sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上。

    二:引入依赖

    <?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>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>ch06</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>ch06</name>
        <description>Demo project for Spring Boot</description>
        <packaging>jar</packaging>
    
        <properties>
            <java.version>1.8</java.version>
            <druid.verzion>1.1.10</druid.verzion>
            <pagehelper.version>1.2.10</pagehelper.version>
            <mybatis.version>2.0.0</mybatis.version>
            <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <!-- 排除默认的tomcat -->
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-tomcat</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <!-- 重新依赖Jetty的starter -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>
    
            <!--shiro整合spring-->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.4.0</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.verzion}</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>${pagehelper.version}</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <!-- spring boot maven插件 -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <!-- 跳过单元测试 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>

    二:yml配置:

    1.application-dao.yml

    # spring整合配置
    spring:
      # 数据源配置
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/weather?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
        username: root
        password: root
        # 使用druid连接池,当使用其他连接池的时候,可以指定type类型为对应的数据源
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
          maxActive: 1000
          initialSize: 10
          maxWait: 1000
          minIdle: 10
          timeBetweenEvictionRunsMillis: 60000
          minEvictableIdleTimeMillis: 300000
          validationQuery: select 1
          testWhileIdle: true
          testOnBorrow: false
          testOnReturn: false
          maxPoolPreparedStatementPerConnectionSize: 0
          # 监控
          stat-view-servlet:
            url-pattern: /druid/*
            reset-enable: false
            login-username: admin
            login-password: admin
            allow: 127.0.0.1
          web-stat-filter:
            url-pattern: /*
            exclusions: /druid/*,*.js,*.css,*.html,*.png,*.jpg
    # mybatis配置
    mybatis:
        type-aliases-package: edu.nf.ch06.entity
        mapper-locations: classpath:/mapper/*.xml
    # 分页插件配置
    pagehelper:
        # 数据库方言
        helper-dialect: mysql
        # 分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页
        reasonable: true
        # 分页参数
        support-methods-arguments: true

    2.application-dao.yml

    # web容器配置
    server:
      # 设置tomcat(如果切换了Jetty,
      # 那么这里换成Jetty的相关配置,并把tomcat的配置注释)
      #tomcat:
      #uri-encoding: UTF-8
      # 指定端口
      port: 8081
      # 指定项目的ContextPath路径,8080后面紧跟着的项目名
      servlet:
        context-path: /ch06
    spring:
      # 配置http字符编码过滤器配置(CharacterEncodingFilter)
      http:
        encoding:
          charset: UTF-8
          enabled: true
          force: true
      # jackson日期格式化和时区设置
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8

    三:导入数据库(这里用city_name当做用户名,city_code做为密码)

     

    /*
     Navicat Premium Data Transfer
    
     Source Server         : 192.168.5.8
     Source Server Type    : MySQL
     Source Server Version : 50723
     Source Host           : localhost:3306
     Source Schema         : weather
    
     Target Server Type    : MySQL
     Target Server Version : 50723
     File Encoding         : 65001
    
     Date: 12/07/2019 16:08:07
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for city_info
    -- ----------------------------
    DROP TABLE IF EXISTS `city_info`;
    CREATE TABLE `city_info`  (
      `city_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '城市编号',
      `city_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '城市名称',
      `city_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '城市编码',
      `province` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '省份',
      `url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`city_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of city_info
    -- ----------------------------
    INSERT INTO `city_info` VALUES (1, '江西', '123', NULL, 'add:user');
    INSERT INTO `city_info` VALUES (2, '广东', '1234', NULL, 'update:user');
    
    SET FOREIGN_KEY_CHECKS = 1;

    四:Controller层

    package edu.nf.ch06.controller;
    
    import edu.nf.ch06.entity.City;
    import edu.nf.ch06.service.CityService;
    import edu.nf.ch06.vo.ResponseVO;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.annotation.Logical;
    import org.apache.shiro.authz.annotation.RequiresPermissions;
    import org.apache.shiro.authz.annotation.RequiresRoles;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    /**
     * @author ywb
     * @date 2019-07-08
     */
    @RestController
    public class CityController extends BaseController{
    
        @Autowired
        private CityService cityService;
    
        @GetMapping("/list_city")
    
        public ResponseVO listCity(){
            List<City> list = cityService.listCity();
            return success(list);
        }
       @RequestMapping(
    "/add") public String add(){ System.out.println("具有添加权限"); return "具有add权限"; } @RequestMapping("/update") public String update(){ System.out.println("具有修改权限"); return "具有update权限"; } @RequestMapping("/test") @RequiresPermissions(value={"weather:city:test","super"}) public String test(){ System.out.println("测试权限"); return "测试注解RequiresPermissions是否有用"; } @RequestMapping("/index") @RequiresRoles(value={"江西"}) public String index(){ System.out.println("修改"); return "江西登入的用户有此权限"; } @RequestMapping("/unAuth") public String unAuth(){ System.out.println("修改"); return "未经授权,无法访问此页面"; } @RequestMapping("/login") public String login(String cityName, String cityCode, Model model){ Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(cityName,cityCode); try { subject.login(token); return "登入成功"; } catch (UnknownAccountException e) { model.addAttribute("msg","用户名不存在"); return "用户名错误"; } catch (IncorrectCredentialsException e) { model.addAttribute("msg","密码错误"); return "密码错误"; } } }

     五:Shiro配置类

    package edu.nf.ch06.shiro;
    
    import org.apache.shiro.mgt.SecurityManager;
    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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Properties;
    
    /**
     * @author : ywb
     * @date : 2019/7/8
     */
    @Configuration
    public class ShiroConfig {
    
    
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            //设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
            //添加一些Shiro的内置过滤器
            /**
             * Shiro 的内置过滤器可以实现权限的相关拦截
             * 常用过滤器
             * 1.anon:无需认证
             * 2.authc:必须认证才能访问
             * 3.user:如果使用rememberme功能可以访问
             * 4.perms:该资源必须得到资源权限才能访问
             * 5.role:该资源必须得到权限资源脆才能访问
             */
            Map<String,String> filterMap =new LinkedHashMap<String,String>();
    //        filterMap.put("/list_city","authc");
    //        filterMap.put("/add","anon");
    //        filterMap.put("/update","anon");
            filterMap.put("/login","anon");
            filterMap.put("/add","perms[add:user]");
            filterMap.put("/update","perms[update:user]");
    //        filterMap.put("list_city","authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
            //授权过滤器
            //注意当授权拦截后,shiro会自动跳转到未授权的页面
    
            //修改调整的登入页面
    //        shiroFilterFactoryBean.setLoginUrl("");
            //登入失败之后需要跳转的页面或需要请求的接口
            shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");
            return shiroFilterFactoryBean;
        }
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("weatherRealm") WeatherRealm weatherRealm){
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            //DefaultWebSecurityManager需要关联一个Realm
            defaultWebSecurityManager.setRealm(weatherRealm);
            return defaultWebSecurityManager;
        }
        /**
         * 创建realm
         */
        @Bean(name = "weatherRealm")
        public WeatherRealm getRealm(){
            return  new WeatherRealm();
        }
    
        /**
         * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
         * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
         * @return
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    
        /**
         * 开启 shiro 的@RequiresPermissions注解
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        /**
         * shiro出现权限异常可通过此异常实现制定页面的跳转(或接口跳转)
         * @return
         */
        @Bean
        public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
            SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
            Properties properties = new Properties();
    
            /*未授权处理页*/
            properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/error.html");
            /*身份没有验证*/
            properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/error.html");
            resolver.setExceptionMappings(properties);
            return resolver;
        }
    
    }

    2.WeatherRealm.java

    package edu.nf.ch06.shiro;
    
    import edu.nf.ch06.dao.CityDao;
    import edu.nf.ch06.entity.City;
    import edu.nf.ch06.service.CityService;
    import org.apache.shiro.SecurityUtils;
    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.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author : ywb
     * @date : 2019/7/8
     */
    public class WeatherRealm extends AuthorizingRealm {
        @Autowired
        private CityService cityService;
        /**
         * 执行授权逻辑
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行授权逻辑");
            //给资源进行授权
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //        info.addStringPermission("user:add");
    
            List<String> roles = new ArrayList<>();
            Subject subject = SecurityUtils.getSubject();
            City city = (City)subject.getPrincipal();
            City dbCity = cityService.findUserById(city.getCityId());
            info.addStringPermission(dbCity.getUrl());
            roles.add(dbCity.getCityName());
            info.addRoles(roles);
            return info;
        }
    
        /**
         * 执行认证逻辑
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    //        String userName = "ywb";
    //        String password = "123";
            UsernamePasswordToken passwordToken = (UsernamePasswordToken)authenticationToken;
            City city =  cityService.getCityByName(passwordToken.getUsername());
            //取出用户名并且判断用户名是否和数据库一致
            if(city==null){
                return  null;//Shiro底层有抛出一个异常表示用户名不存在
            }
            System.out.println("执行认证逻辑");
            //判断密码
            return new SimpleAuthenticationInfo(city,city.getCityCode(),"");
        }
    }

    六:测试

    1.通过用户名:江西 登入的用户具有添加没有修改权限

    2.通过用户名:广东登入的用户具有修改没有添加权限

    3.需要了解更多进入:http://shiro.apache.org/

     

  • 相关阅读:
    第五章 数据的共享与保护
    实验6
    实验5
    实验4 类与对象2)
    实验三 类与对象
    实验2
    2018—3-21第二章程序例题(2)
    第二章思维导图
    2018—3-18C++第二章程序例题
    汇编实验九
  • 原文地址:https://www.cnblogs.com/ywbmaster/p/11176901.html
Copyright © 2011-2022 走看看