四、SpringBoot整合Shiro+MybatisPlus

  1. 原项目继续添加依赖

    		<!--shiro -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>1.4.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.4.1</version>
            </dependency>
            <!--shiro和thymeleaf整合包-->
            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>
    
  2. 自定义UserRealm类用于认证和授权

    package com.jx.config;
      
      import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
      import com.jx.pojo.User;
      import com.jx.service.UserService;
      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.session.Session;
      import org.apache.shiro.subject.PrincipalCollection;
      import org.apache.shiro.subject.Subject;
      import org.springframework.beans.factory.annotation.Autowired;
      
      import java.util.Arrays;
      import java.util.HashSet;
      import java.util.Set;
      
      //自定义Realm
      public class UserRealm extends AuthorizingRealm {
          @Autowired
          private UserService userService;
          //执行授权逻辑
          @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
              System.out.println("执行了=>授权逻辑PrincipalCollection");
              Subject subject = SecurityUtils.getSubject();
              // User currentUser = (User)subject.getPrincipal();//获取认证用户信息 强制转换失败,未知bug,暂无解决方式
              Session session = subject.getSession();
              User currentUser = (User) session.getAttribute("currentUser");//从session中读取user
              String permsArray[] = currentUser.getPerms().split(",");
              System.out.println("获取权限" + permsArray);
              Set<String> permsSet = new HashSet<>(Arrays.asList(permsArray));//以“,”分割权限并转为set
              SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//授权信息类
              info.setStringPermissions(permsSet);//使认证的用户具有访问权限
              return info;
          }
      
          //执行认证逻辑
          @Override
          protected AuthenticationInfo
          doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
              System.out.println("执行了=>认证逻辑AuthenticationToken");
              UsernamePasswordToken userToken = (UsernamePasswordToken) token;//用户输入的数据
              QueryWrapper<User> wrapper = new QueryWrapper<>();//使用mybatisplus条件构造器进行查询
              wrapper.eq("username", userToken.getUsername());
              User user = userService.getOne(wrapper);
              if (user == null) {
                  return null;//数据库中不存在此用户名抛出用户名异常
              }
              Subject subject = SecurityUtils.getSubject();
              Session session = subject.getSession();
              session.setAttribute("currentUser", user);//将user存入session
              String password = user.getPassword();
              return new SimpleAuthenticationInfo("", password, "");//验证密码是否匹配,否则抛出密码错误异常
          }
      }
    
  3. ShiroConfig配置类用于注册Bean和对请求进行拦截

    package com.jx.config;
    
    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    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 UserRealm userRealm() {
            return new UserRealm();
        }
    
        //创建 DefaultWebSecurityManager
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联Realm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        //创建 ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean
        getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
                //设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(securityManager);
        /*
            添加Shiro内置过滤器,常用的有如下过滤器:
            anon: 无需认证就可以访问
            authc: 必须认证才可以访问
            user: 如果使用了记住我功能就可以直接访问
            perms: 拥有某个资源权限才可以访问
            role: 拥有某个角色权限才可以访问
    */
          Map<String,String> filterMap = new LinkedHashMap<String, String>();
    
           filterMap.put("/level1/**","perms[vip1]");//
           filterMap.put("/level2/**","perms[vip2]");
           filterMap.put("/level3/**","perms[vip3]");
           shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);        
           shiroFilterFactoryBean.setLoginUrl("/toLogin");//修改到要跳转的login页面;
            return shiroFilterFactoryBean;
        }
        //整合shiro-thymeleaf
        @Bean
        public ShiroDialect getShiroDialect(){
            return new ShiroDialect();
        }
    }
    
    
  4. 修改User实体类,增加权限属性,数据库增加perms列

    package com.jx.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Integer id;
        private String username;
        private String password;
        private String neckname;
        private String perms;//增加权限属性
    }
    
    

在这里插入图片描述

  1. UserMapper

    package com.jx.mapper;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jx.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import java.util.List;
    @Mapper
    public interface UserMapper extends BaseMapper<User>{
    }
    
    
  2. UserService

    package com.jx.service;
    
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.jx.mapper.UserMapper;
    import com.jx.pojo.User;
    import org.springframework.stereotype.Service;
    
    @Service("userService")
    public class UserService extends ServiceImpl<UserMapper,User> {
    }
    
    
  3. Controller

    package com.jx.controller;
    
    import com.jx.service.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    
    //@RestController//返回字符串
    @Controller
    public class HelloController {
        @Autowired
        private UserService userService;
    
        @RequestMapping({"/index"})
        public String hello() {
            return "index";
        }
    
        @RequestMapping("/login")
        public String login(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            Model model) {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);//封装用户数据
    
            try {
                subject.login(token);//执行登录方法
                return "index";//登录成功
            } catch (UnknownAccountException e) {
                System.out.println("用户名不存在");
                model.addAttribute("msg", "用户名不存在!");
                return "login";//登陆失败
            } catch (IncorrectCredentialsException e) {
                System.out.println("密码错误");
                model.addAttribute("msg", "密码错误!");
                return "login";//登陆失败
            }
        }
    
        @RequestMapping("/toLogin")
        public String toLogin() {
            return "/login";
        }
    
        @RequestMapping("level1/{id}")
        public String toMain1(@PathVariable("id") int id) {
            return "views/level1/" + id;
        }
    
        @RequestMapping("level2/{id}")
        public String toMain2(@PathVariable("id") int id) {
            return "views/level2/" + id;
        }
    
        @RequestMapping("level3/{id}")
        public String toMain3(@PathVariable("id") int id) {
            return "views/level3/" + id;
        }
    
        //注销登录
        @RequestMapping("/logout")
        public String logout() {
            Subject currentUser = SecurityUtils.getSubject();
            currentUser.getSession().removeAttribute("currentUser");
            currentUser.logout();
            return "/login";
        }
    }
    
    
  4. index.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"
          xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <title>首页</title>
        <!--semantic-ui-->
        <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">
        <link th:href="@{/qinjiang/css/qinstyle.css}" rel="stylesheet">
    </head>
    <body>
    
    <!--主容器-->
    <div class="ui container">
    
        <div class="ui segment" id="index-header-nav" th:fragment="nav-menu">
            <div class="ui secondary menu">
                <a class="item" th:href="@{/index}">首页</a>
                <div class="right menu">
                    <!--未登录-->
                    <div th:if="${session.currentUser==null}">
                        <a class="item" th:href="@{/toLogin}">
                            <i class="address card icon"></i> 登录
                        </a>
                    </div>
                    <div th:if="${session.currentUser!=null}">
                        <a class="item" >
                            欢迎您:<span>[[${session.currentUser.username}]]</span>
                        </a>
                    </div>
                    <div th:if="${session.currentUser!=null}">
                        <a class="item" th:href="@{/logout}">
                            <i class="sign-out icon"></i> 注销
                        </a>
                    </div>
                </div>
    
            </div>
        </div>
    
    
        <div class="ui segment" style="text-align: center">
            <h3>Shiro Study </h3>
        </div>
    
        <div>
            <br>
            <div class="ui three column stackable grid">
                <div class="column" shiro:hasPermission='vip1'>
                    <div class="ui raised segment">
                        <div class="ui">
                            <div class="content">
                                <h5 class="content">Level 1</h5>
                                <hr>
                                <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                                <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                                <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
                            </div>
                        </div>
                    </div>
                </div>
    
                <div class="column" shiro:hasPermission='vip2'>
                    <div class="ui raised segment">
                        <div class="ui">
                            <div class="content">
                                <h5 class="content">Level 2</h5>
                                <hr>
                                <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                                <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                                <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
                            </div>
                        </div>
                    </div>
                </div>
    
                <div class="column" shiro:hasPermission='vip3'>
                    <div class="ui raised segment">
                        <div class="ui">
                            <div class="content">
                                <h5 class="content">Level 3</h5>
                                <hr>
                                <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                                <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                                <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
                            </div>
                        </div>
                    </div>
                </div>
    
            </div>
        </div>
    
    </div>
    <script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
    <script th:src="@{/qinjiang/js/semantic.min.js}"></script>
    
    </body>
    </html>
    
  5. 权限控制实现效果

    root1:具有vip1权限

在这里插入图片描述

root2:具有vip1,vip2权限
在这里插入图片描述

root3:具有vip1,vip2,vip3权限

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值