• 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;
          }
      }
      

      运行测试

    还历史以真诚,还生命以过程。 ——余秋雨
  • 相关阅读:
    使用TransactionScope实现事务
    CYQ.Data 框架系列
    MVP
    DYCOM用于开发网络应用程序的通信部分功能的快速开发
    架构师要了解
    Entity Framework资源
    Sina Blogs
    关于TransactionScope出错:“与基础事务管理器的通信失败”的解决方法总结
    在西方的程序员眼里,东方的程序员是什么样的?
    net2.0事务学习
  • 原文地址:https://www.cnblogs.com/w-eye/p/14790621.html
Copyright © 2020-2023  润新知