SpringBoot整合Shiro

SpringBoot整合Shiro

介绍

Shiro和SpringSecurity一样是一个安全框架,使用Shiro可以用在JavaSE环境下,也可以用在JavaEE环境,Shiro可以完成:认证、授权、加密、会话管理、与Web集成、缓存等

三个核心组件:Subject, SecurityManager 和 Realms

  • Subject:即“当前操作用户”。

    Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

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

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

整合SpringBoot

  • 创建SpringBoot项目,勾选web

  • 添加依赖

    <!--shiro安全管理-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.7.1</version>
    </dependency>
    <!-- Thymeleaf依赖 -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-java8time</artifactId>
    </dependency>
    <!--thymeleaf依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
  • 创建html页面

    index

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>首页</h1>
        <hr>
        <p th:text="${msg}"></p>
        <hr>
        <a th:href="@{/user/add}">add</a> | <a th:href="@{/user/add}">update</a>
    </body>
    </html>
    

    login

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>登入</h1>
    <p th:text="${msg}" style="color:#ff0000"></p>
    <form th:action="@{/login}">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="password" name="password"></p>
        <p><input type="submit"></p>
    </form>
    </body>
    </html>
    

    add

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>add</h1>
    </body>
    </html>
    

    update

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>update</h1>
    </body>
    </html>
    
  • controller

    package com.sheep.controller;
    
    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.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    public class MyController {
    
        @RequestMapping({"/","/index"})
        public String toIndex(Model model){
            model.addAttribute("msg","hello,shiro");
            return "index";
        }
    
        @RequestMapping("/user/add")
        public String add(){
            return "user/add";
        }
    
        @RequestMapping("/user/update")
        public String update(){
            return "user/update";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }
    
        @RequestMapping("/login")
        public String login(String username,String password,Model model){
            /*获取当前用户*/
            Subject subject = SecurityUtils.getSubject();
            /*封装用户的登入数据*/
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            /*执行登入的方法,如果没有异常说明ok,捕获异常*/
            try {
                subject.login(token);
                return "index";
            } catch (UnknownAccountException e) {
                model.addAttribute("msg","用户名为空!!!");
                return "login";
            } catch (IncorrectCredentialsException e){
                model.addAttribute("msg","密码为空!!!");
                return "login";
            }
        }
        @RequestMapping("/noauth")
        @ResponseBody
        public String unauthorized(){
            return "未经授权无法访问此页面!!!";
        }
    }
    
  • 要使用shiro需要自定义Realm的授权和认证

    package com.sheep.config;
    
    import com.sheep.pojo.User;
    import com.sheep.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.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /*自定义UserRealm*/
    public class UserRealm extends AuthorizingRealm {
    
        @Autowired
        UserService userService;
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了=>授权(doGetAuthorizationInfo)");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //给所有人添加user:add权限
    		info.addStringPermission("user:add");
            return info;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了=>认证(doGetAuthenticationInfo)");
            /*
             * 用户名、密码、数据库中取
             * */
            /*
             * 自定义数据库
             * */
            String name="root";
            String password="123456";
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            if(!userToken.getUsername().equals(name)){
                return null;/*用户名错误,shiro自动抛出异常;密码认证shiro自动认证*/
            }
            /*密码认证,Shiro会自动密码认证*/
            return new SimpleAuthenticationInfo("",password,"");
        }
    }
    
    
  • shiro配置类

    package com.sheep.config;
    
    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 {
        /**
         * 1、创建自定义的realm对象
         * 2、DafaultWebSecurityManager
         * 3、ShiroFilterFactoryBean
         * */
        /*自定义的realm对象*/
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
        /*DafaultWebSecurityManager*/
        @Bean
        public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
        /*ShiroFilterFactoryBean*/
        @Bean
        public ShiroFilterFactoryBean getsShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //过滤请求
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*添加shiro的内置过滤器*/
            /*
             * anno:无需认证可以访问
             * authc:必须认证才能访问
             * user:必须拥有记住我功能才能访问
             * perms:拥有对某个资源的权限才能访问
             * role:拥有某个角色权限才能访问
             * */
            Map<String, String> filterMap = new LinkedHashMap<>();
            //授权
            filterMap.put("/user/add","perms[user:add]");
           	//方法一
            //filterMap.put("/user/add","authc");
            //filterMap.put("/user/update","authc");
            //方法二
            filterMap.put("/user/*","authc");
            bean.setFilterChainDefinitionMap(filterMap);
            /*设置登入请求*/
            bean.setLoginUrl("/toLogin");
            /*设置未授权页面*/
            bean.setUnauthorizedUrl("/noauth");
            return bean;
        }
    }
    
  • 测试

整合MyBatis

  • 导入要整合MyBatis的依赖

    <!--简化实体类-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--整合mybatis-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.6</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>
    
  • 创建表

    +----------+-------------+------+-----+---------+----------------+
    | Field    | Type        | Null | Key | Default | Extra          |
    +----------+-------------+------+-----+---------+----------------+
    | id       | int         | NO   | PRI | NULL    | auto_increment |
    | username | varchar(5)  | YES  |     | NULL    |                |
    | password | varchar(6)  | YES  |     | NULL    |                |
    | perms    | varchar(20) | YES  |     | NULL    |                |
    +----------+-------------+------+-----+---------+----------------+
    
  • 创建表对应的实体类

    package com.sheep.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String username;
        private String password;
        private String perms;
    }
    
  • 创建接口

    package com.sheep.mapper;
    
    import com.sheep.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.springframework.stereotype.Repository;
    
    @Mapper
    @Repository
    public interface UserMapper {
        public User queryUserByName(String username);
    }
    
  • service层接口

    package com.sheep.service;
    
    import com.sheep.pojo.User;
    
    public interface UserService {
        public User queryUserByName(String username);
    }
    
  • service实现接口

    package com.sheep.service;
    
    import com.sheep.mapper.UserMapper;
    import com.sheep.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        UserMapper userMapper;
    
        @Override
        public User queryUserByName(String username) {
            return userMapper.queryUserByName(username);
        }
    }
    
  • 测试连接数据库是否成功

    package com.sheep;
    
    import com.sheep.service.UserServiceImpl;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class DemoApplicationTests {
    
        @Autowired
        UserServiceImpl userService;
    
        @Test
        void contextLoads() {
            System.out.println(userService.queryUserByName("root"));
        }
    }
    
  • 在resources文件夹下创建mapper.XML文件

    <mapper namespace="com.sheep.mapper.UserMapper">
        <select id="queryUserByName" parameterType="String" resultType="com.sheep.pojo.User">
            select * from user where username = #{username}
        </select>
    </mapper>
    
  • application.properties配置连接数据库信息

    # 配置数据库信息
    spring.datasource.username=root
    spring.datasource.password=123321
    spring.datasource.url=jdbc:mysql://localhost:3306/junit?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    # mybatis配置文件
    mybatis.type-aliases-package=com.sheep.pojo
    mybatis.mapper-locations=classpath:mapper/*.XML
    
  • 在自定义的Realm中使用数据库数据判断

    package com.sheep.config;
    
    import com.sheep.pojo.User;
    import com.sheep.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.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /*自定义UserRealm*/
    public class UserRealm extends AuthorizingRealm {
    
        @Autowired
        UserService userService;
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了=>授权(doGetAuthorizationInfo)");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    		//info.addStringPermission("user:add");
            //获取当前对象
            Subject subject = SecurityUtils.getSubject();
            //获取user对象
            User currentUser =(User) subject.getPrincipal();
            //设置当前用户的权限
            info.addStringPermission(currentUser.getPerms());
            return info;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了=>认证(doGetAuthenticationInfo)");
            /*
             * 用户名、密码、数据库中取
             * */
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            //连接数据库
            User user = userService.queryUserByName(userToken.getUsername());
            if(user==null){
                //如果没有该用户返回null
                return null;
            }
            /*
             * 自定义数据库
             * */
            //String name="root";
            //String password="123456";
            //UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            //if(!userToken.getUsername().equals(name)){
            //    return null;/*用户名错误,shiro自动抛出异常;密码认证shiro自动认证*/
            //}
            /*密码认证,Shiro会自动密码认证*/
            return new SimpleAuthenticationInfo("",user.getPassword(),"");
        }
    }
    
    package com.sheep.config;
    
    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 {
        /**
         * 1、创建realm对象 :自定义
         * 2、DafaultWebSecurityManager
         * 3、ShiroFilterFactoryBean
         * */
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
        @Bean
        public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
        @Bean
        public ShiroFilterFactoryBean getsShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //过滤请求
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*添加shiro的内置过滤器*/
            /*
             * anno:无需认证可以访问
             * authc:必须认证才能访问
             * user:必须拥有记住我功能才能访问
             * perms:拥有对某个资源的权限才能访问
             * role:拥有某个角色权限才能访问
             * */
            Map<String, String> filterMap = new LinkedHashMap<>();
            //授权.如果未授权跳转到授权页面
            filterMap.put("/user/add","perms[user:add]");
            /*
             * 方法-
             * filterMap.put("/user/add","authc");
             * filterMap.put("/user/update","authc");
             * */
            /*方法二*/
            filterMap.put("/user/*","authc");
            bean.setFilterChainDefinitionMap(filterMap);
            /*设置登入请求*/
            bean.setLoginUrl("/toLogin");
            /*设置未授权页面*/
            bean.setUnauthorizedUrl("/noauth");
            return bean;
        }
    }
    

    运行测试

posted @ 2021-05-20 17:11  一程山水一年华^_^  阅读(89)  评论(0编辑  收藏  举报
TOP 底部 /*显示代码块行号*/